英文:
How to convert a Boost.Beast request<string_body> to a request<file_body>?
问题
我正在编写一个boost::beast
服务器,但我在如何使用不同的请求类型方面遇到了困难。
当连接被接受时,我会这样读取请求:
- 调用
async_read()
,填充我的request<string_body>
- 查看请求的方法和目标,以将其分派给能够处理该请求的对象
然而,有些方法(比如当用户想要上传/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:
- I call
async_read()
, which populates myrequest<string_body>
- 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<Session>
{
tcp_steam stream;
flat_buffer buf;
request<string_body> req;
public:
Session(boost::asio::ip::tcp::socket&& socket)
: stream(std::move(socket) ) {}
void Read() {
req = request<string_body>{}
async_read(stream, buf, req,
bind_front_handler(&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<file_body>
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<Body>
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<empty_body> 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] != "application/x-www-form-urlencoded" &&
req0.get()[field::content_type] != "multipart/form-data")
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<string_body> 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<dynamic_body> 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;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论