HTTP POST 请求不允许我定义上下文类型
HTTP POST request won't let me define context type
我正在使用 Ubuntu 18.04 和 boost.asio 发送 POST 请求休息一下 API。当服务器收到请求时,它会捕获它,但我似乎无法定义它的内容类型。我有一个函数 collectRequestData
应该解析请求的主体,然后将其 return 保存到 MySQL 数据库中。当我打印函数 returns 时,它打印 null
而它应该是它发送的 JSON 文本。当我在调用函数之前打印 "Content-Type"
时,当我认为它应该是 "application/json"
时它打印未定义。我的最终目标是当我 运行 我的客户端代码 ./file.o localhost 8080 /licence '{JSON formatted text}'
它连接到本地主机端口 8080 路径 /licence (它正确执行)然后将 JSON 文本保存到 MySQL 数据库。它没有正确执行,我很确定原因是 "Content-Type"
我是使用服务器和 JavaScript 的新手,所以如果有人看到我做错了什么,请指出。另外,如果您能提供额外的细节以帮助我理解建议,我们将不胜感激。
下面是我发送 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;
}
下面是我的服务器处理 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);
}
}
您缺少行尾
request_stream << "User-Agent: C/1.0";
应该是
request_stream << "User-Agent: C/1.0\r\n";
表示您的内容类型 header 永远不会被识别,因为它不在单独的行上
我假设您正在为服务器使用 nodeJS
nodejs 给你小写的请求头
所以
function collectRequestData(request, callback) {
console.log(request.headers['content-type']);
const FORM_URLENCODED = 'application/json';
if(request.headers['content-type'] === FORM_URLENCODED) {
let body = '';
一旦您解决了@john 指出的其他问题,当然
即
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";
感觉是网络服务器的问题,你可能不符合http协议规范。尝试使用 boost::beast,在 boost 1.66 及以上版本中可用。它是 boost::asio 的包装器,添加了高级网络服务器和网络套接字功能。您无需为低级 HTTP 实现而烦恼。
首先,我认为你应该仔细检查服务器是否正确。提供一种方法:
curl "http://localhost:8080/licence" --data "{json format text}" -v
如果此命令返回的结果与您的相同,则为服务器问题。
如果不行,请尝试assemble你代码中的请求包内容与curl相同,尤其是“\r\n”等。
正确的解决方案是@john 和@Jaromanda X 所说的组合,我还必须将 const FORM_URLENCODED = 'application/json';
更改为 const FORM_URLENCODED = 'application/json; charset=utf-8'
我正在使用 Ubuntu 18.04 和 boost.asio 发送 POST 请求休息一下 API。当服务器收到请求时,它会捕获它,但我似乎无法定义它的内容类型。我有一个函数 collectRequestData
应该解析请求的主体,然后将其 return 保存到 MySQL 数据库中。当我打印函数 returns 时,它打印 null
而它应该是它发送的 JSON 文本。当我在调用函数之前打印 "Content-Type"
时,当我认为它应该是 "application/json"
时它打印未定义。我的最终目标是当我 运行 我的客户端代码 ./file.o localhost 8080 /licence '{JSON formatted text}'
它连接到本地主机端口 8080 路径 /licence (它正确执行)然后将 JSON 文本保存到 MySQL 数据库。它没有正确执行,我很确定原因是 "Content-Type"
我是使用服务器和 JavaScript 的新手,所以如果有人看到我做错了什么,请指出。另外,如果您能提供额外的细节以帮助我理解建议,我们将不胜感激。
下面是我发送 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;
}
下面是我的服务器处理 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);
}
}
您缺少行尾
request_stream << "User-Agent: C/1.0";
应该是
request_stream << "User-Agent: C/1.0\r\n";
表示您的内容类型 header 永远不会被识别,因为它不在单独的行上
我假设您正在为服务器使用 nodeJS
nodejs 给你小写的请求头
所以
function collectRequestData(request, callback) {
console.log(request.headers['content-type']);
const FORM_URLENCODED = 'application/json';
if(request.headers['content-type'] === FORM_URLENCODED) {
let body = '';
一旦您解决了@john 指出的其他问题,当然
即
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";
感觉是网络服务器的问题,你可能不符合http协议规范。尝试使用 boost::beast,在 boost 1.66 及以上版本中可用。它是 boost::asio 的包装器,添加了高级网络服务器和网络套接字功能。您无需为低级 HTTP 实现而烦恼。
首先,我认为你应该仔细检查服务器是否正确。提供一种方法:
curl "http://localhost:8080/licence" --data "{json format text}" -v
如果此命令返回的结果与您的相同,则为服务器问题。 如果不行,请尝试assemble你代码中的请求包内容与curl相同,尤其是“\r\n”等。
正确的解决方案是@john 和@Jaromanda X 所说的组合,我还必须将 const FORM_URLENCODED = 'application/json';
更改为 const FORM_URLENCODED = 'application/json; charset=utf-8'