Boost Beast:当内容长度不容易获得时,如何使用自定义正文生成非分块响应?

Boost Beast: how to produce non-chunked response with a custom body when a content length is not readily available?

我正在尝试实现一个自定义主体类型,该主体类型将包含已解析的 JSON 树对象。这个任务看起来很自然,但我找不到使用 Beast 生成携带 JSON 的非分块 HTTP 消息的方法。我有一个通过包装 libmicrohttpd 和 libcurl 实现的 REST client/server,但我更愿意改用 Boost Beast。

据我了解,问题是正文类型的 size(value_type const&) 方法接收到对要序列化的正文值的引用(在我的例子中是 JSON 树对象),但是如果不实际将其字符串化,则无法确定字符串化 JSON 的确切长度。但是,如果我删除 size() 方法,Beast 认为我要求的是分块传输编码。当然,分块编码本身并没有什么问题,但对我来说,这可能意味着修复一些自动化和监控脚本,更不用说集成测试了。

我想做的是将一个JSON对象分配给我正在准备的消息,然后Beast去询问作者,而不是body::size() 用于有效负载大小。这对我来说似乎合乎逻辑,因为实际的 HTTP 消息正文(序列化 JSON)与内存中的活动 JSON 对象完全不同,它是 body::writer 谁产生用于传输的正文字节。我错了吗?

无论如何,你认为有好的方法来解决这个问题吗?

预先感谢您的时间和精力!

此致, 弗拉德

感谢您的美言,我很高兴看到 Body 自定义系统受到关注!你在问题中写的大部分内容都是正确的。如果您希望 Beast 在您调用 message::prepare_payload 时设置 Content-Length 字段,那么您必须在 Body::size 中提供正确的实现。 BodyWriter 直到序列化时才创建。这个问题最自然的解决方案是避免提供 Body::size 并让 Beast 在序列化您的 body 类型时使用分块的 Transfer-Encoding。我还应该注意,当您序列化 JSON 时,最好是在 writer 中一次做一点而不是将整个事物转换为字符串。这就是让编写器 object 保持中间状态并允许增量序列化的目的。否则,您必须为整个序列化表示分配内存,效率较低。

更新:

body::size()message::prepare_payload 并非旨在按照您希望的方式使用。如果我明白你想做什么,那么这个函数应该处理它:

/** Prepare a message with a JSON payload.

    This function accepts ownership of a message with a JSON body
    and converts the JSON to string, returning a new message with
    a string body. The Content-Length field is set on the new
    message. All other fields are transferred over unmodified.
*/
template<
    bool isRequest,
    class Allocator>
message<
    isRequest,
    string_body,
    basic_fields<Allocator>>
prepare(
    message<
        isRequest,
        json_body,
        basic_fields<Allocator>>&& m)
{
    message<
        isRequest,
        string_body,
        basic_fields<Allocator>> result{
            std::move(m.base()),
            json_to_string(m.body())};
    result.prepare_payload();
    return result;
}