如何将 Boost.Beast 的 request 转换为 request

huangapple go评论69阅读模式
英文:

How to convert a Boost.Beast request<string_body> to a request<file_body>?

问题

我正在编写一个boost::beast服务器,但我在如何使用不同的请求类型方面遇到了困难。

当连接被接受时,我会这样读取请求:

  1. 调用async_read(),填充我的request<string_body>
  2. 查看请求的方法和目标,以将其分派给能够处理该请求的对象

然而,有些方法(比如当用户想要上传/POST一个二进制文件时)我怀疑会更好地接收一个request<file_body>

在这些方法中,我可以将request<string_body>转换为request<file_body>吗?

如果不能,那么在创建请求对象之前如何知道请求的方法/目标?似乎没有办法在事先不知道request<Body>中的Body的情况下调用async_read

英文:

I'm writing a boost::beast server, and I'm having trouble figuring out how to use the different request flavours.

When a connection is accepted, I do this to read the request:

  1. I call async_read(), which populates my request&lt;string_body&gt;
  2. I look at the request's method and target to dispatch it to whoever can handle that request
using namespace boost::beast::http;
using namespace boost::beast;

class Session : public enable_shared_from_this&lt;Session&gt;
{

    tcp_steam            stream;
    flat_buffer          buf;
    request&lt;string_body&gt; req;
    
public:
    Session(boost::asio::ip::tcp::socket&amp;&amp; socket) 
        : stream(std::move(socket) ) {}
    
    void Read() {
    
        req = request&lt;string_body&gt;{}

        async_read(stream, buf, req, 
            bind_front_handler(&amp;Session::OnRead, shared_from_this() ) 
        );
    }
    
    void OnRead(error_code ec, size_t)
    {
        auto method = GetRoute( req.target(), req.method() );
        method( std::move(req) );
    }
};

However, some of those methods (like when a user wants to upload/POST a binary file) I suspect would work better if they received a request&lt;file_body&gt;

Can I convert the request<string_body> to a request<file_body> in those methods?

If not, how can I know the request's method/target before creating the request object? It doesn't seem like there is a way to call async_read without knowing the Body in request&lt;Body&gt; ahead of time.

答案1

得分: 2

这里的想法是先读取头部,然后决定消息体的类型,然后切换。

为此,专门提供了一种用于切换消息体类型的转换构造函数,并在这里进行了文档记录 更改消息体类型。它附带了一个相关的示例,如下所示:

// 从empty_body解析器开始
request_parser<empty_body> req0;

// 仅读取头部。否则,如果接收到了消息体字节,empty_body将生成错误。
read_header(stream, buffer, req0);

// 根据方法动词选择消息体类型
switch(req0.get().method())
{
case verb::post:
{
// 如果这不是表单上传,则使用string_body
if( req0.get()[field::content_type] != "application/x-www-form-urlencoded" &&
req0.get()[field::content_type] != "multipart/form-data")
goto do_dynamic_body;

// 将string_body作为消息体类型。
// 只要从中构造的解析器中没有消息体字节,就不会抛出异常。
request_parser<string_body> req{std::move(req0)};

// 完成消息的读取
read(stream, buffer, req);

// 调用处理程序。如果需要,它可以获取所有权,
// 因为我们在调用release()。
handler(req.release());
break;

}

do_dynamic_body:
default:
{
// 将dynamic_body作为消息体类型。
// 只要从中构造的解析器中没有消息体字节,就不会抛出异常。
request_parser<dynamic_body> req{std::move(req0)};

// 完成消息的读取
read(stream, buffer, req);

// 调用处理程序。如果需要,它可以获取所有权,
// 因为我们在调用release()。
handler(req.release());
break;

}
}

英文:

The idea here is to read the headers first, then decide on the body type, and switch.

There is a body-type-switching conversion constructor specifically for this purpose, and it is documented here Change Body Type. It comes with an example, relevant excerpt:

// Start with an empty_body parser
request_parser&lt;empty_body&gt; req0;

// Read just the header. Otherwise, the empty_body
// would generate an error if body octets were received.
read_header(stream, buffer, req0);

// Choose a body depending on the method verb
switch(req0.get().method())
{
case verb::post:
{
    // If this is not a form upload then use a string_body
    if( req0.get()[field::content_type] != &quot;application/x-www-form-urlencoded&quot; &amp;&amp;
        req0.get()[field::content_type] != &quot;multipart/form-data&quot;)
        goto do_dynamic_body;

    // Commit to string_body as the body type.
    // As long as there are no body octets in the parser
    // we are constructing from, no exception is thrown.
    request_parser&lt;string_body&gt; req{std::move(req0)};

    // Finish reading the message
    read(stream, buffer, req);

    // Call the handler. It can take ownership
    // if desired, since we are calling release()
    handler(req.release());
    break;
}

do_dynamic_body:
default:
{
    // Commit to dynamic_body as the body type.
    // As long as there are no body octets in the parser
    // we are constructing from, no exception is thrown.
    request_parser&lt;dynamic_body&gt; req{std::move(req0)};

    // Finish reading the message
    read(stream, buffer, req);

    // Call the handler. It can take ownership
    // if desired, since we are calling release()
    handler(req.release());
    break;
}

huangapple
  • 本文由 发表于 2023年6月8日 19:10:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76431225.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定