Boost asio 自定义 HTTP 服务器读取 HTTP post 请求
Boost asio custom HTTP server reading HTTP post requests
我的 C++ 应用程序需要一个 HTTP 服务器,我决定自己制作一个,它在发送 HTTP Get 请求时可以正常工作,但在读取 HTTP Post 请求时会出现一些问题。
问题是在发送 HTTP Posts 请求时,最后的 header 没有被正确读取,所以我无法获得 post 请求。
这是我的代码:
void HttpSession::readHeaders(std::shared_ptr<HttpSession> pThis) {
boost::asio::async_read_until(pThis->socket_, pThis->buff_, '\r\n\r\n',
[pThis](const boost::system::error_code &e, std::size_t s) {
std::istream headersStream(&pThis->buff_);
std::string header;
while(std::getline(headersStream, header, '\n')) {
if(header != "\r") {
if(header.back() == '\r') header = header.substr(0, header.length() - 1);
qDebug() << QString::fromStdString(header);
//Some stuff to get content-length to contentLength_
}
}
if(contentLength_ > 0) {
qDebug() << "Reading:";
readBody(pThis);
}
std::shared_ptr<std::string> str = std::make_shared<std::string>(pThis->headers_.getResponse());
boost::asio::async_write(pThis->socket_, boost::asio::buffer(str->c_str(), str->length()),
[pThis, str](const boost::system::error_code &e, std::size_t s) {
qDebug() << "Written";
});
}
void HttpSession::readBody(std::shared_ptr<HttpSession> pThis) {
boost::asio::async_read(pThis->socket_, pThis->data_, boost::asio::transfer_at_least(1),
[pThis](const boost::system::error_code &e, std::size_t s) {
std::istream body(&pThis->data_);
std::string line;
body >> line;
qDebug() << QString::fromStdString(line);
});
}
buff_
和 data_
变量声明为:boost::asio::streambuf
。而 HttpSession
class 是存储 header 并处理所有网页服务的那个。我没有包含那个 class 的代码,因为这不是问题所在。
对 /url 的 HTTP Post 请求的输出是这个:
"POST /url HTTP/1.1"
"Host: 192.168.1.41:8080"
"Connection: keep-alive"
"Content-Length: 10"
"Cache-Control: max-age=0"
"Origin: http://192.168.1.41:8080"
"Upgrade-Insecure-Requests: 1"
"User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"
"Content-Type: application/x-www-form-urlencoded"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
"Referer: http://192.168.1.41:8080/"
"Accept-Encoding: gzip, deflate"
"Accept-Langua"
Reading:
"ge:"
如您所见,Accept-Language header 未正确读取,尽管在此图中您可以看到 POST 请求已正确发出。
请注意,发送 GET 请求时一切正常。所以我的猜测是它与异步读取有关,因为 async_read_until
不会阻塞,所以 readBody
函数的 async_read
在它应该读取之前读取。那我应该同步阅读吗?如果我为每个客户端创建一个 HttpSession class,我是否能够以任何一种方式处理多个客户端? (我真的不需要支持一个以上的用户,但是,这会很好)。
对于客户端处理我是这样的:
void HttpServer::run() {
using namespace boost::asio;
io_service io_service;
ip::tcp::endpoint endpoint{ip::tcp::v4(), 8080};
ip::tcp::acceptor acceptor{io_service, endpoint};
acceptor.listen();
runServer(acceptor, io_service);
io_service.run();
while(true) QThread::msleep(5000);
}
void HttpServer::runServer(boost::asio::ip::tcp::acceptor& acceptor, boost::asio::io_service& io_service) {
std::shared_ptr<HttpSession> ses = std::make_shared<HttpSession>(io_service);
acceptor.async_accept(ses->socket_,
[ses, &acceptor, &io_service](const boost::system::error_code& accept_error) {
runServer(acceptor, io_service);
if(!accept_error) HttpSession::interact(ses);
});
}
我们将不胜感激!如果您有任何代码改进,请告诉我。谢谢!
我认为问题出在 '\r\n\r\n'
。那不是字符串而是 char
.
编译器通常会警告您这一点,例如:
warning: implicit conversion from 'int' to 'char' changes value from 218762506 to 10 [-Wconstant-conversion]
尝试将其替换为 "\r\n\r\n"
。
我的 C++ 应用程序需要一个 HTTP 服务器,我决定自己制作一个,它在发送 HTTP Get 请求时可以正常工作,但在读取 HTTP Post 请求时会出现一些问题。
问题是在发送 HTTP Posts 请求时,最后的 header 没有被正确读取,所以我无法获得 post 请求。
这是我的代码:
void HttpSession::readHeaders(std::shared_ptr<HttpSession> pThis) {
boost::asio::async_read_until(pThis->socket_, pThis->buff_, '\r\n\r\n',
[pThis](const boost::system::error_code &e, std::size_t s) {
std::istream headersStream(&pThis->buff_);
std::string header;
while(std::getline(headersStream, header, '\n')) {
if(header != "\r") {
if(header.back() == '\r') header = header.substr(0, header.length() - 1);
qDebug() << QString::fromStdString(header);
//Some stuff to get content-length to contentLength_
}
}
if(contentLength_ > 0) {
qDebug() << "Reading:";
readBody(pThis);
}
std::shared_ptr<std::string> str = std::make_shared<std::string>(pThis->headers_.getResponse());
boost::asio::async_write(pThis->socket_, boost::asio::buffer(str->c_str(), str->length()),
[pThis, str](const boost::system::error_code &e, std::size_t s) {
qDebug() << "Written";
});
}
void HttpSession::readBody(std::shared_ptr<HttpSession> pThis) {
boost::asio::async_read(pThis->socket_, pThis->data_, boost::asio::transfer_at_least(1),
[pThis](const boost::system::error_code &e, std::size_t s) {
std::istream body(&pThis->data_);
std::string line;
body >> line;
qDebug() << QString::fromStdString(line);
});
}
buff_
和 data_
变量声明为:boost::asio::streambuf
。而 HttpSession
class 是存储 header 并处理所有网页服务的那个。我没有包含那个 class 的代码,因为这不是问题所在。
对 /url 的 HTTP Post 请求的输出是这个:
"POST /url HTTP/1.1"
"Host: 192.168.1.41:8080"
"Connection: keep-alive"
"Content-Length: 10"
"Cache-Control: max-age=0"
"Origin: http://192.168.1.41:8080"
"Upgrade-Insecure-Requests: 1"
"User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"
"Content-Type: application/x-www-form-urlencoded"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
"Referer: http://192.168.1.41:8080/"
"Accept-Encoding: gzip, deflate"
"Accept-Langua"
Reading:
"ge:"
如您所见,Accept-Language header 未正确读取,尽管在此图中您可以看到 POST 请求已正确发出。
请注意,发送 GET 请求时一切正常。所以我的猜测是它与异步读取有关,因为 async_read_until
不会阻塞,所以 readBody
函数的 async_read
在它应该读取之前读取。那我应该同步阅读吗?如果我为每个客户端创建一个 HttpSession class,我是否能够以任何一种方式处理多个客户端? (我真的不需要支持一个以上的用户,但是,这会很好)。
对于客户端处理我是这样的:
void HttpServer::run() {
using namespace boost::asio;
io_service io_service;
ip::tcp::endpoint endpoint{ip::tcp::v4(), 8080};
ip::tcp::acceptor acceptor{io_service, endpoint};
acceptor.listen();
runServer(acceptor, io_service);
io_service.run();
while(true) QThread::msleep(5000);
}
void HttpServer::runServer(boost::asio::ip::tcp::acceptor& acceptor, boost::asio::io_service& io_service) {
std::shared_ptr<HttpSession> ses = std::make_shared<HttpSession>(io_service);
acceptor.async_accept(ses->socket_,
[ses, &acceptor, &io_service](const boost::system::error_code& accept_error) {
runServer(acceptor, io_service);
if(!accept_error) HttpSession::interact(ses);
});
}
我们将不胜感激!如果您有任何代码改进,请告诉我。谢谢!
我认为问题出在 '\r\n\r\n'
。那不是字符串而是 char
.
编译器通常会警告您这一点,例如:
warning: implicit conversion from 'int' to 'char' changes value from 218762506 to 10 [-Wconstant-conversion]
尝试将其替换为 "\r\n\r\n"
。