POST请求正文为空(cpp-netlib 0.13.0)

时间:2018-02-23 10:26:37

标签: c++ boost cpp-netlib

我已将cpp-netlib从v0.11.0升级到0.13.0并遇到了一些困难。

以前,当请求发送到服务器时,可以从请求对象中读取请求的正文。

当我使用v0.13.0向服务器发送相同的请求时,请求正文现在为空。

请求对象的其余部分似乎是正确的 - 只有正文是空的。

我需要做些什么不同的事情吗?我无法在网站上找到任何显示身体如何被提取的例子。

我已经从hello world示例中确认了相同的行为。

#include <boost/network/protocol/http/server.hpp>
#include <iostream>

namespace http = boost::network::http;

struct hello_world;
typedef http::server<hello_world> server;

struct hello_world
{
    void operator()(const server::request  &request, server::connection_ptr connection)
    {
        ///////////////////////////////////
        // request.body is empty
        ///////////////////////////////////

        server::string_type ip = source(request);
        unsigned int port = request.source_port;

        std::ostringstream data;
        data << "Hello, " << ip << ':' << port << '!';
        connection->set_status(server::connection::ok);
        connection->write(data.str());
    }
};

int main(int argc, char *argv[]) {

    try {
        hello_world handler;
        server::options options(handler);
        server server_(options.address("192.168.0.19").port("9999"));

        server_.run();
    }
    catch (std::exception &e) {
        std::cerr << e.what() << std::endl;
        return 1;
    }

    return 0;
}

以下是我发送的请求:

13 C url -v -X POST http://192.168.0.19:9999/my-app/rest/foo/1.0/bar -H 'Content-Type: application/x-www-form-urlencoded' --data key=value

3 个答案:

答案 0 :(得分:2)

在较早版本的cpp-netlib中,您可以在sync_serverasync_server类之间进行选择。从版本0.12开始,仅async_server类可用。此类不会自动将POST请求的正文数据读入request.body,但要求用户使用connection->read(callback)以异步方式读取数据。 / p>

长话短说,我编译了一个 minimum 回显服务器示例,该示例显示了如何正确执行此操作。它还说明了如何处理可能涉及的未知的Expect: 100-continue标头。

请检出echo_async_server.cpp,它最近已添加到仓库中。

答案 1 :(得分:1)

#include <vector>

#include <boost/config/warning_disable.hpp>
#include <boost/network/include/http/server.hpp>
#include <boost/network/utils/thread_pool.hpp>
#include <boost/range/algorithm/find_if.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>

namespace net = boost::network;
namespace http = boost::network::http;
namespace utils = boost::network::utils;

struct async_hello_world;
typedef http::async_server<async_hello_world> server;

struct connection_handler : boost::enable_shared_from_this<connection_handler> {

    connection_handler(server::request const &request)
        :req(request), body("") {}

    ~connection_handler() {
        std::cout << "connection_handler dctor called!" << std::endl;
    }

    void operator()(server::connection_ptr conn) {
        int cl;
        server::request::headers_container_type const &hs = req.headers;
        for(server::request::headers_container_type::const_iterator it = hs.begin(); it!=hs.end(); ++it) {
            if(boost::to_lower_copy(it->name)=="content-length") {
                cl = boost::lexical_cast<int>(it->value);
                break;
            }
        }

        read_chunk(cl, conn);
    }

    void read_chunk(size_t left2read, server::connection_ptr conn) {
        std::cout << "left2read: " << left2read << std::endl;
        conn->read(
            boost::bind(
                &connection_handler::handle_post_read,
                connection_handler::shared_from_this(),
                _1, _2, _3, conn, left2read
                )
            );
    }

    void handle_post_read(
        server::connection::input_range range, boost::system::error_code error, size_t size, server::connection_ptr conn, size_t left2read) {
        if(!error) {
            std::cout << "read size: " << size << std::endl;
            body.append(boost::begin(range), size);
            size_t left = left2read - size;
            if(left>0) {
                read_chunk(left, conn);
            } else {
                //std::cout << "FINISHED at " << body.size()<< std::endl;
            }

        }
        std::cout << "error: " << error.message() << std::endl;
    }

    void handle_post_request(server::connection_ptr conn)
    {
        std::cout << "handle request..." << std::endl;
        std::cout << "post size: " << body.size() << std::endl;
    }

    server::request const &req;
    std::string body;
};


struct async_hello_world {

    void operator()(server::request const &request, server::connection_ptr conn) {
    boost::shared_ptr<connection_handler> h(new connection_handler(request));
    (*h)(conn);
    }

    void error(boost::system::error_code const & ec) {
        // do nothing here.
    std::cout << "async error: " << ec.message() << std::endl;
    }
};

int main(int argc, char * argv[]) {
    utils::thread_pool thread_pool(4); 
    async_hello_world handler;
    server instance("0.0.0.0", "1935", handler, thread_pool);
    instance.run();
    return 0;
}

答案 2 :(得分:0)

您需要手动阅读正文。现在使用了connection_ptr对象,并且必须附加处理程序才能执行读取。

所以看起来应该是这样的:

if (r.method == "POST") {
            auto foundIt = std::find_if(r.headers.begin(), r.headers.end(),
                                        [](auto const & h) { return h.name == "Content-Length"; });
            if (foundIt == r.headers.end())
                throw std::logic_error("No Content-Length header found in POST");

            auto handleReadFunc = [this](auto &&... args) {
                this->handleReadBody(args...);
            };

            //This attaches a callback to read the body
            connection->read(handleReadFunc);
        }