c++ - 如何使用 C++ 和 Boost Asio 从 HTTP 发布请求中获取键值
问题描述
我接到了一项任务,其中涉及使用 c++ 和 Boost Asio 库编写 Web 服务器。
我已经将工作服务器放在一起,它可以使用一本名为“Boost.Asio C++ Network Programming Cookbook”的书将 html 文件发送回客户端浏览器,但我在处理来自客户端的 POST 请求时遇到了困难。
当客户端连接到服务器时,他们会收到简单的 HTML 表单,其中包含用户名和密码字段以登录服务器,然后使用 POST 请求将其发送到服务器。
我已经将收到的 POST 请求的内容输出到控制台,可以看到所有的 header 信息,但是看不到表单数据。我已经使用 Wireshark 来检查数据包,并且数据正在通过网络发送。
服务器正在接收数据作为 Boost Asio 流缓冲区,我正在解析它以通过将其读入向量然后获取相关元素(例如方法或目标)来获取请求的 HTML 文件。
有人对在哪里寻找有关如何解析表单数据的教程有任何建议吗?
下面的代码是解析 POST 请求并根据请求内容处理响应的 cpp 文件的一部分。'&request' 参数是 Boost Asio streambuf
我在网络编程方面的经验很少,如果有任何建议,我将不胜感激!
解析请求的代码
// Prepare and return the response message.
// Parse the request from the client to find requested document
std::istream buffer(&request);
std::vector<std::string> parsed((std::istream_iterator<std::string>(buffer)), std::istream_iterator<std::string>() );
处理 POST 请求
else if (parsed.size() >= 3 && parsed[0] == "POST") {
htmlFile = "/files.html";
// Retrieve files from server file system. The second element in 'parsed' vector is file name
std::ifstream fileStream(".\\directory" + htmlFile);
// If the file exists then iterate it and assign the value to the content string variable, else return 404.
if (fileStream.good()) {
std::string fileContents((std::istreambuf_iterator<char>(fileStream)), std::istreambuf_iterator<char>());
content = fileContents;
code = "200 ok";
}
else {
std::ifstream fileStream(".\\directory\\404.html");
std::string fileContents((std::istreambuf_iterator<char>(fileStream)), std::istreambuf_iterator<char>());
content = fileContents;
code = "404";
}// End of nested if-else statement
}// End of else-if statement
else {
std::ifstream fileStream(".\\directory\\401.html");
std::string fileContents((std::istreambuf_iterator<char>(fileStream)), std::istreambuf_iterator<char>());
content = fileContents;
code = "401";
// Write bad request to log file for security audits if not "GET" request
logging.logAction("Illegal request by client IP " + m_sock->remote_endpoint().address().to_string());
}//End of if-else statement
std::ostringstream oss;
oss << "GET HTTP/1.1 " << code << " \r\n";
oss << "Cache-Control: no-cache, private" << "\r\n";
oss << "Content-Type: text/html" << "\r\n";
oss << "Content-Length: " << content.size() << "\r\n";
oss << "\r\n\r\n";
oss << content;
response = oss.str().c_str();
解决方案
HTTP 是一种逐行协议。示例:https ://www.tutorialspoint.com/http/http_requests.htm
POST /cgi-bin/process.cgi HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)
Host: www.tutorialspoint.com
Content-Type: application/x-www-form-urlencoded
Content-Length: length
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
licenseID=string&content=string&/paramsXML=string
您需要更具体地进行解析,而不是将每个空格分隔的“单词”放入向量中。
从这样的事情开始:
#include <iostream>
#include <iomanip>
#include <boost/asio.hpp>
int main() {
boost::asio::streambuf request;
{
std::ostream sample(&request);
sample <<
"POST /cgi-bin/process.cgi HTTP/1.1\r\n"
"User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)\r\n"
"Host: www.tutorialspoint.com\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"Content-Length: 49\r\n"
"Accept-Language: en-us\r\n"
"Accept-Encoding: gzip, deflate\r\n"
"Connection: Keep-Alive\r\n"
"\r\n"
"licenseID=string&content=string&/paramsXML=string"
;
}
std::istream buffer(&request);
std::string line;
// parsing the headers
while (getline(buffer, line, '\n')) {
if (line.empty() || line == "\r") {
break; // end of headers reached
}
if (line.back() == '\r') {
line.resize(line.size()-1);
}
// simply ignoring headers for now
std::cout << "Ignore header: " << std::quoted(line) << "\n";
}
std::string const body(std::istreambuf_iterator<char>{buffer}, {});
std::cout << "Parsed content: " << std::quoted(body) << "\n";
}
印刷
Ignore header: "POST /cgi-bin/process.cgi HTTP/1.1"
Ignore header: "User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)"
Ignore header: "Host: www.tutorialspoint.com"
Ignore header: "Content-Type: application/x-www-form-urlencoded"
Ignore header: "Content-Length: 49"
Ignore header: "Accept-Language: en-us"
Ignore header: "Accept-Encoding: gzip, deflate"
Ignore header: "Connection: Keep-Alive"
Parsed content: "licenseID=string&content=string&/paramsXML=string"
推荐阅读
- c# - 隐藏或显示子游戏对象
- c# - 不能将 HtmlAgilityPack 与多线程一起使用
- php - 为什么MYSQL不起作用?
- mongodb - MongoDB数据库创建问题
- c# - 如何在 WPF 中获取 TreeView 的单击节点的标题?
- excel - OneDrive for Business 上的 Excel 刷新失败
- c# - 如何在 C# 中验证 ASP.NET 中继器中的多个单选按钮
- c# - C# Winforms RDLC 报告静态交叉表列
- ruby-on-rails-5 - 在 webpacker 中解析 rails 图像 url
- javascript - 在 Angular 5 中切换兄弟组件