HTTP POST-запрос не позволит мне определить тип контекста
Я использую Ubuntu 18.04 и boost.asio для отправки запроса POST в API отдыха. Когда сервер получает запрос, он ловит его, но я не могу определить его тип контента. У меня есть функция collectRequestData
предполагается, что он анализирует тело запроса и возвращает его там, где он затем сохраняется в базе данных MySQL. Когда я печатаю то, что возвращает функция, она печатает null
когда это должен быть текст JSON, который был отправлен. Когда я печатаю "Content-Type"
перед вызовом функции она печатает неопределенную, когда я думаю, что это должно быть "application/json"
, Моя конечная цель здесь, когда я запускаю свой клиентский код ./file.o localhost 8080 /licence '{JSON formatted text}'
он подключается к локальному порту 8080 путь / лицензия (что он делает правильно), а затем сохраняет текст 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);
}
}
5 ответов
Правильное решение - это сочетание того, что сказали @john и @Jaromanda X, и мне также пришлось изменить const FORM_URLENCODED = 'application/json';
в const FORM_URLENCODED = 'application/json; charset=utf-8'
Вам не хватает конца строки
request_stream << "User-Agent: C/1.0";
должно быть
request_stream << "User-Agent: C/1.0\r\n";
Означает, что ваш заголовок типа контента никогда не распознается, потому что он не находится на отдельной строке
Возможно, проблема с веб-сервером. Возможно, вы не соответствует спецификации протокола http. Попробуйте использовать boost:: beast, доступный в boost 1.66 и более. Это оболочка над boost:: asio, которая добавляет функциональность веб-сервера и сокетов высокого уровня. Вам не нужно беспокоиться о низкоуровневой реализации HTTP.
Я предполагаю, что вы используете 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, конечно
т.е.
Вам не хватает конца строки
request_stream << "User-Agent: C/1.0";
должно быть
request_stream << "User-Agent: C/1.0\r\n";
Прежде всего, я думаю, вы должны дважды проверить, является ли сервер правильным или нет. Предлагая один метод:
curl "http://localhost:8080/licence" --data "{json format text}" -v
Если эта команда отвечает тем же результатом, что и ваш, это проблема сервера. Если нет, попробуйте собрать тот же контент пакета запроса в вашем коде, что и curl, особенно "\r\n" и так далее.