基于Beast的Http服务器基本流程

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数据,包括 erroremailmsg 字段。
  • 将响应的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_contextacceptorsocket,并启动服务器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值