Boost::Beast::Http服务器
命名空间和类型定义
namespace beast = boost::beast; namespace http = beast::http; namespace net = boost::asio; using tcp = boost::asio::ip::tcp;
这些命名空间和类型定义简化了后续代码的书写。
命名空间 my_program_state
namespace my_program_state { std::size_t request_count() { static std::size_t count = 0; return ++count; } std::time_t now() { return std::time(0); } }
这个命名空间包含两个函数:
request_count()
:返回请求计数,每次调用时递增。now()
:返回当前时间。
类 http_connection
这个类处理每个HTTP连接,继承自 std::enable_shared_from_this
以便在异步操作中安全地创建 shared_ptr
。
构造函数和 start
方法
http_connection(tcp::socket socket) : m_socket(std::move(socket)) { } void start() { read_request(); check_deadline(); }
构造函数接受一个TCP套接字。start
方法启动读取请求和超时检测。
私有成员变量
tcp::socket m_socket; beast::flat_buffer m_buffer{ 8192 }; http::request<http::dynamic_body> m_request; http::response<http::dynamic_body> m_response; net::steady_timer m_deadline{m_socket.get_executor(), std::chrono::seconds(60)};
这些成员变量包括套接字、缓冲区、请求和响应对象,以及一个超时定时器。
read_request
方法
void read_request() { auto self = shared_from_this(); http::async_read(m_socket, m_buffer, m_request, self { if (!ec) { self->process_request(); } }); }
这个方法异步读取HTTP请求,并在读取完成后调用 process_request
方法。
check_deadline
方法
void check_deadline() { auto self = shared_from_this(); m_deadline.async_wait(self { if (!ec) { self->m_socket.close(ec); } }); }
这个方法设置一个超时定时器,如果超时则关闭套接字。
process_request
方法
void process_request() { m_response.version(m_request.version()); m_response.keep_alive(false); switch (m_request.method()) { case http::verb::get: m_response.result(http::status::ok); m_response.set(http::field::server, "Beast"); create_response(); break; case http::verb::post: m_response.result(http::status::ok); m_response.set(http::field::server, "Beast"); create_post_response(); break; default: m_response.result(http::status::bad_request); m_response.set(http::field::content_type, "text/plain"); beast::ostream(m_response.body()) << "Invalid request-method" << std::string(m_request.method_string()) << "`" << std::endl; break; } write_response(); }
这个方法处理HTTP请求,根据请求方法生成响应。
create_response
方法
void create_response() { if (m_request.target() == "/count") { m_response.set(http::field::content_type, "text/html"); beast::ostream(m_response.body()) << "<html>\n" << "<head><title>Request count</title></head>\n" << "<body>\n" << "<h1>Request count</h1>\n" << "<p>There have been " << my_program_state::request_count() << " requests so far.</p>\n" << "</body>\n" << "</html>\n"; } else if (m_request.target() == "/time") { m_response.set(http::field::content_type, "text/html"); beast::ostream(m_response.body()) << "<html>\n" << "<head><title>Current time</title></head>\n" << "<body>\n" << "<h1>Current time</h1>\n" << "<p>The current time is " << my_program_state::now() << " seconds since the epoch.</p>\n" << "</body>\n" << "</html>\n"; } else { m_response.result(http::status::not_found); m_response.set(http::field::content_type, "text/plain"); beast::ostream(m_response.body()) << "File not found\r\n"; } }
这个方法根据请求的目标生成不同的响应内容。
write_response
方法
void write_response() { auto self = shared_from_this(); m_response.content_length(m_response.body().size()); http::async_write(m_socket, m_response, self { self->m_socket.shutdown(tcp::socket::shutdown_send, ec); self->m_deadline.cancel(); }); }
这个方法异步写入HTTP响应,并在完成后关闭套接字。
create_post_response
方法
void create_post_response() { if (m_request.target() == "/email") { auto& body = this->m_request.body(); auto body_str = beast::buffers_to_string(body.data()); std::cout << "receive body is " << body_str << std::endl; this->m_response.set(http::field::content_type, "text/json"); Json::Value root; Json::Reader reader; Json::Value src_root; bool parse_success = reader.parse(body_str, src_root); if (!parse_success) { std::cout << "Failed to parse Json data" << std::endl; root["error"] = 1001; std::string jsonstr = root.toStyledString(); beast::ostream(m_response.body()) << jsonstr; return; } auto email = src_root["email"].asString(); std::cout << "email is" << email << std::endl; root["error"] = 0; root["email"] = src_root["email"]; root["msg"] = "receive email post success"; std::string jsonstr = root.toStyledString(); beast::ostream(m_response.body()) << jsonstr; } else { m_response.result(http::status::not_found); m_response.set(http::field::content_type, "text/plain"); beast::ostream(m_response.body()) << "File not found\r\n"; } }
这个方法处理POST请求,解析JSON数据并生成响应。
方法概述
create_post_response
方法根据请求的目标路径处理POST请求。如果目标路径是 /email
,则解析请求体中的JSON数据,并生成相应的响应。如果目标路径不是 /email
,则返回404 Not Found响应。
代码解析
检查请求目标
if (m_request.target() == "/email")
这行代码检查HTTP请求的目标路径是否为 /email
。
获取请求体
auto& body = this->m_request.body(); auto body_str = beast::buffers_to_string(body.data()); std::cout << "receive body is " << body_str << std::endl;
auto& body = this->m_request.body();
获取请求体的引用。auto body_str = beast::buffers_to_string(body.data());
将请求体转换为字符串。std::cout << "receive body is " << body_str << std::endl;
打印接收到的请求体内容。
设置响应头
this->m_response.set(http::field::content_type, "text/json");
设置响应的内容类型为 text/json
。
解析JSON数据
Json::Value root; Json::Reader reader; Json::Value src_root; bool parse_success = reader.parse(body_str, src_root); if (!parse_success) { std::cout << "Failed to parse Json data" << std::endl; root["error"] = 1001; std::string jsonstr = root.toStyledString(); beast::ostream(m_response.body()) << jsonstr; return; }
Json::Value root;
和Json::Value src_root;
定义两个JSON对象。Json::Reader reader;
定义一个JSON解析器。bool parse_success = reader.parse(body_str, src_root);
解析请求体中的JSON数据,并将结果存储在src_root
中。- 如果解析失败,设置错误信息并返回响应。
处理解析后的数据
auto email = src_root["email"].asString(); std::cout << "email is" << email << std::endl; root["error"] = 0; root["email"] = src_root["email"]; root["msg"] = "receive email post success"; std::string jsonstr = root.toStyledString(); beast::ostream(m_response.body()) << jsonstr;
auto email = src_root["email"].asString();
获取解析后的JSON数据中的email
字段。- 打印接收到的
email
。 - 设置响应的JSON数据,包括
error
、email
和msg
字段。 - 将响应的JSON数据转换为字符串,并写入响应体。
处理未找到的目标路径
else { m_response.result(http::status::not_found); m_response.set(http::field::content_type, "text/plain"); beast::ostream(m_response.body()) << "File not found\r\n"; }
如果请求的目标路径不是 /email
,则返回404 Not Found响应,并设置响应体为 “File not found”。
总结
create_post_response
方法处理HTTP POST请求,解析请求体中的JSON数据,并生成相应的响应。如果请求的目标路径不是 /email
,则返回404 Not Found响应。
http_server` 函数
void http_server(tcp::acceptor& acceptor, tcp::socket& socket) { acceptor.async_accept(socket, & { if (!ec) { std::make_shared<http_connection>(std::move(socket))->start(); } http_server(acceptor, socket); }); }
这个函数接受新的连接并创建 http_connection
对象来处理每个连接。
main
函数
int main() { try { auto const address = net::ip::make_address("127.0.0.1"); unsigned short port = static_cast<unsigned short>(8080); net::io_context ioc{1}; tcp::acceptor acceptor{ ioc,{address,port} }; tcp::socket socket{ ioc }; http_server(acceptor, socket); ioc.run(); } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; return EXIT_FAILURE; } }
这个函数设置服务器的IP地址和端口,创建 io_context
、acceptor
和 socket
,并启动服务器。