使用 Boost::URL 进行请求路由和 JSON 响应的 Boost::Beast 最小 HTTP 服务器示例

在我们之前的文章使用 boost::json 的 Boost::Beast 最小 HTTP 服务器示例中,我们展示了一个基于 Boost::Beast 的现代 C++ Web 服务器的最小示例。

在这篇文章中,我们将扩展示例以使用 Boost::URL 包含请求路由。

请求路由 HOWTO

路由请求很简单:

httpserver.cpp
url_view parsed_url(req.target());
auto params = parsed_url.params();

// NOTE: Path is /api/login for the example above
auto path = parsed_url.path();

if(path == "/hello") {
    // TODO: Handle /hello
} else if(path == "/world") {
    // TODO: Handle /world
} else {
        res.result(http::status::not_found);
        res.set(http::field::content_type, "text/plain");
        res.body() = "Not Found";
        res.prepare_payload();
}

完整示例

httpserver.cpp
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/asio.hpp>
#include <boost/json.hpp>
#include <boost/url.hpp>
#include <iostream>

using namespace boost::urls;
using std::cout, std::endl;

#include <iostream>

namespace beast = boost::beast;     // from <boost/beast.hpp>
namespace http = beast::http;      // from <boost/beast/http.hpp>
namespace net = boost::asio;       // from <boost/asio.hpp>
namespace json = boost::json;      // from <boost/json.hpp>
using tcp = boost::asio::ip::tcp;  // from <boost/asio/ip/tcp.hpp>

// Function to handle an HTTP request and generate a JSON response
void handle_request(const http::request<http::string_body>& req, http::response<http::string_body>& res) {
    // For this example, only GET request
    if (req.method() == http::verb::get) {
        // NOTE: For http://127.0.0.1:8080/api/login?username=myusername&password=mypassword
        // req.target() will be /api/login?username=myusername&password=mypassword
        url_view parsed_url(req.target());
        auto params = parsed_url.params();

        // NOTE: Path is /api/login for the example above
        auto path = parsed_url.path();

        if(path == "/hello") {
            json::object json_response;
            json_response["message"] = "Hello, World!";
            json_response["status"] = "success";

            res.result(http::status::ok);
            res.set(http::field::content_type, "application/json");
            res.body() = json::serialize(json_response);
            res.prepare_payload();
        } else if(path == "/world") {
            json::object json_response;
            json_response["message"] = "World, Hello!";
            json_response["status"] = "success";

            res.result(http::status::ok);
            res.set(http::field::content_type, "application/json");
            res.body() = json::serialize(json_response);
            res.prepare_payload();
        } else {
            res.result(http::status::not_found);
            res.set(http::field::content_type, "text/plain");
            res.body() = "Not Found";
            res.prepare_payload();
        }
    } else {
        res.result(http::status::method_not_allowed);
        res.set(http::field::content_type, "text/plain");
        res.body() = "Method Not Allowed";
        res.prepare_payload();
    }
}

// Session to handle communication with a single client
void session(tcp::socket socket) {
    try {
        beast::flat_buffer buffer;

        // Read an HTTP request
        http::request<http::string_body> req;
        http::read(socket, buffer, req);

        // Prepare the response
        http::response<http::string_body> res;
        handle_request(req, res);

        // Write the response
        http::write(socket, res);
    } catch (const std::exception& e) {
        std::cerr << "Error in session: " << e.what() << '\n';
    }
}

// Main function to set up the server
int main() {
    try {
        const auto address = net::ip::make_address("127.0.0.1");
        const unsigned short port = 8080;

        net::io_context ioc;

        // Create and bind the acceptor
        tcp::acceptor acceptor{ioc, {address, port}};
        std::cout << "HTTP server is running on http://127.0.0.1:8080\n";

        while (true) {
            // Accept a new connection
            tcp::socket socket{ioc};
            acceptor.accept(socket);

            // Handle the session in a new thread
            std::thread{&session, std::move(socket)}.detach();
        }
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << '\n';
        return 1;
    }
}

如何编译

build-httpserver.sh
g++ -std=c++17 -O2 httpserver.cpp -o httpserver -lboost_system -lboost_url -lboost_thread -lboost_json -lpthread

如何测试

在终端中运行:

run-httpserver.sh
./httpserver

打开浏览器并访问 http://127.0.0.1:8080/hellohttp://127.0.0.1:8080/world 查看 JSON 响应。


Check out similar posts by category: Boost, C/C++