从一个简单的POST请求解析异常

时间:2018-09-17 03:33:10

标签: c++ docker elasticsearch

我正在使用C ++中的套接字与Elasticsearch通信。我可以与我的ELK实例通信(它在docker compose中运行,docker文件为here)。

这是我发送的请求:

POST /twitter/_doc/1? HTTP/1.1
Content-Type: application/json; charset=UTF-8
Host: 127.0.0.1:9200
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
'{ "post_date" : "2017-11-16T14:12:12", "message" : "trying out Elasticsearch FROM CPPPPP" }'
Connection: close

这是我从服务器获得的响应:

HTTP/1.1 400 Bad Request
content-type: application/json; charset=UTF-8
content-length: 163

{"error":{"root_cause":[{"type":"parse_exception","reason":"request body is required"}],"type":"parse_exception","reason":"request body is required"},"status":400}

我可以通过计算发送和接收的字节数来确认我正在发送和接收此数据。

我很困惑,因为当我将该请求放入Kibana控制台时,它运行良好。

关于我发送的请求有什么问题的任何想法?

这是我创建请求的C ++代码:

std::string post_http = "";
post_http += "POST /twitter/_doc/1? HTTP/1.1\n";
post_http += "Content-Type: application/json; charset=UTF-8\n";
post_http += "Host: ";
post_http += aURL;
post_http += ":9200\n";
post_http += "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\n";
post_http += "'{ \"post_date\" : \"2017-11-16T14:12:12\", ";
post_http += "\"message\" : \"trying out Elasticsearch FROM CPPPPP\" }'";
post_http += "\r\nConnection: close\r\n\r\n";

据我所知,在上面的代码中如何创建请求将是一个问题。

2 个答案:

答案 0 :(得分:0)

根据您的代码,您似乎在标头中混入了正文。 因此,您的HTTP消息中实际上没有正文。

请参阅https://en.wikipedia.org/wiki/HTTP_message_body,以了解HTTP消息的构成方式,尤其要注意需要pof在标头和正文之间具有EMPTY行。

对于您而言,一种解决方案可能是将您的post_http字符串更改为:

std::string post_http = "";
post_http += "POST /twitter/_doc/1? HTTP/1.1\r\n";
post_http += "Content-Type: application/json; charset=UTF-8\r\n";
post_http += "Host: " + aURL + ":9200\r\n";
post_http += "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\r\n";
post_http += "Connection: close\r\n"
post_http += "\r\n"; // EMPTY line between header and body.
post_http += "'{ \"post_date\" : \"2017-11-16T14:12:12\", ";
post_http += "\"message\" : \"trying out Elasticsearch FROM CPPPPP\" }'";

我还更改了行尾,使之与链接文章中指定的全部一致“ \ r \ n”。

它也可能有助于定义一个字符串const,以给行结束序列起一个名字,例如:

const char* HTTP_LINE_END = "\r\n";

答案 1 :(得分:0)

问题来自于标题中没有Content-Body,以及套接字等待响应多长时间。似乎与WinSock documentation相反,如果您正在等待服务器的响应,则不应调用shutdown方法。

这是我最终完成的方法所拥有的:

assert(strcmp(aMethod, "GET") || strcmp(aMethod, "POST") || strcmp(aMethod, "PUT"));

// TODO: Investigate if I actually need to reconnect the socket every time a request is made? 
ConnectSocket();

char Request[MAX_REQUEST_LEN];
strcpy_s(Request, MAX_REQUEST_LEN, aMethod);

strcat_s(Request, MAX_REQUEST_LEN, " ");
strcat_s(Request, MAX_REQUEST_LEN, aIndexParam);
strcat_s(Request, MAX_REQUEST_LEN, RequestHeader);

strcat_s(Request, MAX_REQUEST_LEN, "Content-Length: ");
strcat_s(Request, MAX_REQUEST_LEN, std::to_string(strlen(aMsg)).c_str());
strcat_s(Request, MAX_REQUEST_LEN, "\r\n");

strcat_s(Request, MAX_REQUEST_LEN, ConnectionClose);
strcat_s(Request, MAX_REQUEST_LEN, aMsg);
strcat_s(Request, MAX_REQUEST_LEN, "\r\n");

如您所见,我转而使用char *而不是std::String,这使我的性能提高了30%。另外,标头中现在有一个Content-Length标签。

这是我最终的标题:

POST /twitter/_doc/ HTTP/1.1
Content-Type: application/json; charset=UTF-8
Content-Encoding: identity
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
Host:  HTTP/1.1
127.0.0.1:9200
Content-Length: 112
Connection: close

{ "user" : "kimchy", "post_date" : "2018-09-16T14:12:12", "message" : "trying out Elasticsearch FROM c++ BOII" }