c++ - 如何使用 C++ 和 Boost Asio 从 HTTP post 请求获取键值

标签 c++ http server boost-asio

我收到了一项作业,其中涉及使用 C++ 和 Boost Asio 库编写 Web 服务器。

我已经组装了一个工作服务器,它可以使用一本名为“Boost.Asio C++ Network Programming Cookbook”的书将 html 文件发送回客户端浏览器,但我正在努力处理来自客户端的 POST 请求。

当客户端连接到服务器时,他们会获得简单的 HTML 表单,其中包含用于登录服务器的用户名和密码字段,然后使用 POST 请求将其发送到服务器。

我已经将收到的POST请求的内容输出到控制台,我可以看到所有的 header 信息,但看不到表单数据。我已使用 Wireshark 检查数据包,并且数据正在通过网络发送。

服务器以 Boost Asio Streambuf 的形式接收数据,我通过将其读入 vector 然后获取相关元素(例如方法或目标)来解析它以获取请求的 HTML 文件。

有人对在哪里寻找有关如何解析表单数据的教程有任何建议吗?

下面的代码是 cpp 文件的一部分,它解析 POST 请求并根据请求的内容处理响应。 '&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 是一种逐行协议(protocol)。 sample :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

您需要进行更具体的解析,而不是将每个空格分隔的“单词”放入 vector 中。

从这样的事情开始:

Live On Coliru

#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++ 和 Boost Asio 从 HTTP post 请求获取键值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59659968/

相关文章:

c++ - gcc c++ 命令行错误消息解析器

flash - Haxe http 请求违反安全沙箱

http - 当 Web 服务器返回 JPEG 图像(mime 类型图像/jpeg)时,它是如何编码的?

python - python TCP服务器中的主要功能没有生成输出

c - C语言的TCP客户端和服务器

c++ - 我怎样才能 boost::bind 到传递并返回 std::string 的托管类的成员?

c++ - 将虚函数添加到类声明的末尾可以避免二进制不兼容?

c++ - 如何优化这个将输入位转换为单词的简单函数?

http - Angular2的resolveAndCreate HTTP - RC7中缺少HTTP_PROVIDERS

python - 用于插入文本小视频的服务器要求 ffmpeg