简体   繁体   English

HTTP POST请求不会让我定义上下文类型

[英]HTTP POST request won't let me define context type

I'm using Ubuntu 18.04 and boost.asio to send a POST request to a rest API. 我正在使用Ubuntu 18.04boost.asio将POST请求发送到rest API。 When the server is receiving the request it catches it but I can't seem to define its content type. 当服务器接收到请求时,它将捕获该请求,但是我似乎无法定义其内容类型。 I have a function collectRequestData that is supposed to parse the body of the request and return it where it is then saved to a MySQL database. 我有一个函数collectRequestData ,它应该解析请求的主体并将其返回,然后将其保存到MySQL数据库中。 When I print what the function returns it prints null when it should be the JSON text it was sent. 当我打印函数返回的内容时,当它应该是发送的JSON文本时,它会输出null When I print the "Content-Type" before the function is called it prints undefined when I think it should be "application/json" . 当我在调用函数之前打印"Content-Type"时,当我认为它应该是"application/json"时,它会打印未定义的内容。 My end goal here is when I run my client code by ./file.o localhost 8080 /licence '{JSON formatted text}' it connects to localhost port 8080 path /licence (which it does correctly) and then saves the JSON text to the MySQL database. 我的最终目标是当我通过./file.o localhost 8080 /licence '{JSON formatted text}'运行客户端代码时,它将连接到localhost端口8080路径/ licence(它可以正确执行),然后将JSON文本保存到MySQL数据库。 Which it is not doing correctly and I'm pretty sure the cause is the "Content-Type" I'm new to working with servers and JavaScript so if anyone sees me doing something wrong please point it out. 它不能正常运行,我可以肯定原因是服务器和JavaScript刚接触"Content-Type" ,因此如果有人看到我做错了,请指出。 Also if you could give extra detail to help me understand a suggestion it would be much appreciated. 另外,如果您能提供更多详细信息以帮助我理解建议,也将不胜感激。


Below is my client code that sends the POST request 以下是我发送POST请求的客户端代码

#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;
using namespace std;

int main(int argc, char* argv[])
{
    cout << "main -start" << endl;
    try
    {
        boost::asio::io_service io_service;
        string ipAddress = argv[1]; //"localhost" for loop back or ip address otherwise, i.e.- www.boost.org;       
        string portNum = argv[2]; //"8000" for instance;
        string hostAddress;
        if (portNum.compare("80") != 0) // add the ":" only if the port number is not 80 (proprietary port number).
        {
            hostAddress = ipAddress + ":" + portNum;
        }
        else 
        { 
            hostAddress = ipAddress;
        }
        string wordToQuery = "";//this will be used for entry indexing
        string queryStr = argv[3]; //"/api/v1/similar?word=" + wordToQuery;
        string json = argv[4];

        // Get a list of endpoints corresponding to the server name.
        tcp::resolver resolver(io_service);
        tcp::resolver::query query(ipAddress, portNum);
        tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

        // Try each endpoint until we successfully establish a connection.
        tcp::socket socket(io_service);
        boost::asio::connect(socket, endpoint_iterator);

        // Form the request. We specify the "Connection: close" header so that the
        // server will close the socket after transmitting the response. This will
        // allow us to treat all data up until the EOF as the content.
        string typeJSON = application/json;
        boost::asio::streambuf request;
        std::ostream request_stream(&request);
        request_stream << "POST " << queryStr << " HTTP/1.1\r\n";  // note that you can change it if you wish to HTTP/1.0
        request_stream << "Host: " << hostAddress << "\r\n";
        request_stream << "User-Agent: C/1.0";
        request_stream << "Content-Type: application/json; charset=utf-8\r\n";
        request_stream << "Accept: */*\r\n";
        request_stream << "Content-Length: " << json.length() << "\r\n"; 
        request_stream << "Connection: close\r\n\r\n";
        request_stream << json;

        // Send the request.
        boost::asio::write(socket, request);

        // Read the response status line. The response streambuf will automatically
        // grow to accommodate the entire line. The growth may be limited by passing
        // a maximum size to the streambuf constructor.
        boost::asio::streambuf response;
        boost::asio::read_until(socket, response, "\r\n");

        // Check that response is OK.
        std::istream response_stream(&response);
        std::string http_version;
        response_stream >> http_version;
        unsigned int status_code;
        response_stream >> status_code;
        std::string status_message;
        std::getline(response_stream, status_message);
        if (!response_stream || http_version.substr(0, 5) != "HTTP/")
        {
            std::cout << "Invalid response\n";
            return 1;
        }
        if (status_code != 200)
        {
            std::cout << "Response returned with status code " << status_code << "\n";
            return 1;
        }

        // Read the response headers, which are terminated by a blank line.
        boost::asio::read_until(socket, response, "\r\n\r\n");

        // Process the response headers.
        std::string header;
        while (std::getline(response_stream, header) && header != "\r")
        {
            std::cout << header << "\n";
        }

        std::cout << "\n";

        // Write whatever content we already have to output.
        if (response.size() > 0)
        {
            std::cout << &response;
        }

        // Read until EOF, writing data to output as we go.
        boost::system::error_code error;
        while (boost::asio::read(socket, response,boost::asio::transfer_at_least(1), error))
        {
            std::cout << &response;
        }

        if (error != boost::asio::error::eof)
        {
            throw boost::system::system_error(error);
        }
    }
    catch (std::exception& e)
    {
        std::cout << "Exception: " << e.what() << "\n";
    }

    return 0;
}

Below is the part of my server that handles the POST request 以下是我的服务器中处理POST请求的部分

app.post('/licence', function (req, res) {
    collectRequestData(req, result => {
        //console.log(request.headers['Content-Type']);
        console.log(result);
        sleep(5000);
        connection.query('INSERT INTO licence SET ?', result, function (error, results) {
            if (error) throw error;
            res.end(JSON.stringify(results));
        });
        //res.end(`Parsed data belonging to ${result.fname}`);
    });
});

function collectRequestData(request, callback) {
    console.log(request.headers['Content-Type']);
    const FORM_URLENCODED = 'application/json';
    if(request.headers['Content-Type'] === FORM_URLENCODED) {
        let body = '';
        request.on('data', chunk => {
            body += chunk.toString();
        });
        request.on('end', () => {
            callback(JSON.parse(body));
        });
    }
    else {
        callback(null);
    }
}

You are missing an end of line 您错过了行尾

request_stream << "User-Agent: C/1.0";

should be 应该

request_stream << "User-Agent: C/1.0\r\n";

Means your content type header never gets recognised because it isn't on a separate line 意味着您的内容类型标头永远不会被识别,因为它不在单独的行中

It feels a web-server issue, you are probably not compliant with the http protocol specification. 感觉是网络服务器问题,您可能不符合http协议规范。 Try using boost::beast, available in boost 1.66 and over. 尝试使用boost :: beast,可在boost 1.66及更高版本中使用。 It's a wrapper over boost::asio that adds high level web-server and web-socket functionality. 它是boost :: asio的包装,它增加了高级Web服务器和Web套接字功能。 You don't need to bother with low-level HTTP implementation. 您无需为低级HTTP实施而烦恼。

sample code 样例代码

I'm assuming you're using nodeJS for the server 我假设您正在使用nodeJS作为服务器

nodejs gives you the request header in lower case nodejs为您提供小写的请求标头

so 所以

function collectRequestData(request, callback) {
    console.log(request.headers['content-type']);
    const FORM_URLENCODED = 'application/json';
    if(request.headers['content-type'] === FORM_URLENCODED) {
        let body = '';

once you fix the other issue identified by @john, of course 当然,一旦解决了@john标识的其他问题,

ie

You are missing an end of line 您错过了行尾

request_stream << "User-Agent: C/1.0";

should be 应该

request_stream << "User-Agent: C/1.0\\r\\n";

First of all, i think you should double check whether the server is right or not. 首先,我认为您应该仔细检查服务器是否正确。 Offering one method: 提供一种方法:

curl "http://localhost:8080/licence" --data "{json format text}" -v

If this command responses the same result as yours, it is the problem of server. 如果此命令响应的结果与您的结果相同,则是服务器问题。 If not, try to assemble the same request package content in your code as the curl, especially "\\r\\n" and so on. 如果不是,请尝试在代码中汇编与curl相同的请求包内容,尤其是“ \\ r \\ n”等。

The correct solution is a combination of what @john and @Jaromanda X said and I also had to change const FORM_URLENCODED = 'application/json'; 正确的解决方案是@john和@Jaromanda X所说的结合,我还必须更改const FORM_URLENCODED = 'application/json'; to const FORM_URLENCODED = 'application/json; charset=utf-8' const FORM_URLENCODED = 'application/json; charset=utf-8' const FORM_URLENCODED = 'application/json; charset=utf-8'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM