使用boost库中的asio创建支持post请求的HTTP服务

本文介绍如何使用Boost.ASIO库改进HTTP服务以正确处理POST请求。通过修改示例代码,使得服务端能够接收并解析POST请求的全部数据。文章详细说明了必要的代码更改,并分享了完整的代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用C++创建HTTP服务有一个比较好的选择,就是使用boost库中的asio模块,官网上提供了创建HTTP服务的例子,链接地址
在这里插入图片描述
官网提供的例子可以直接运行,但却存在一个问题,对于接收GET请求,是正常的,但是对于POST请求会返回出错,原因在于POST请求是有两次TCP的数据传送,而GET请求只有一次,而示例程序并没有对post请求的进行单独处理。
针对以上问题,我在官网的例子上进行修改,使之可以接收post请求的数据,主要地方在于更改connection.cpp中的do_read函数。
更改的地方如下:
第一处在connection.hpp中添加几个类的公有变量:
在这里插入图片描述

			vector<string> v_data;//保存请求头和请求体数据
			request request_first;//第一次的请求
			request_parser::result_type result_first;//第一次的请求结果

第二处的为重点,更改connection.cpp中的do_read函数实现过程:
在这里插入图片描述

void connection::do_read()
		{
			auto self(shared_from_this());
			socket_.async_read_some(boost::asio::buffer(buffer_),
				[this, self](boost::system::error_code ec, std::size_t bytes_transferred)
			{
				if (!ec)
				{
					request_parser::result_type result;
					std::tie(result, std::ignore) = request_parser_.parse(
						request_, buffer_.data(), buffer_.data() + bytes_transferred);
					/*
					如果是get请求,原代码就没问题
					如果是post请求,这个就只能接收第一次请求
					因为get请求是一次tcp 而post请求是两次tcp
					对于post请求,第二次tcp获取得到的result和request并满足发送数据的要求,
					应该使用post请求的第一条数据
					*/
					string data = buffer_.data();
					buffer_ = { '\0' };//清空buffer
					if (v_data.size() == 0)
					{
						v_data.push_back("hhc");
						request_first = request_;
						result_first = result;
						if (request_first.method == "POST")
						{
							//有的时候一次post请求就可以接收所有的数据
							smatch result1;
							regex r1("\r\n\r\n.*");
							string s1 = data;
							string::const_iterator it_start = s1.begin();
							string::const_iterator it_end = s1.end();
							string body;
							while (regex_search(it_start, it_end, result1, r1))
							{
								body = result1[0];
								it_start = result1[0].second;

							}
							if (!body.empty())
							{
								data = body.substr(4, body.length());
								if (!data.empty())
								{
									//一次数据接收就完成了
								}
								else {
									//需要两次数据才接收完
									do_read();
									return;
								}
							}
						}
					}

					if (result_first == request_parser::good)
					{
						v_data.clear();
						//保存请求体数据 只有post请求才需要保存
						if (request_first.method == "POST")
						{
							request_first.body = data;
						}

						request_handler_.handle_request(request_first, reply_);
						do_write();
					}
					else if (result_first == request_parser::bad)
					{
						v_data.clear();
						reply_ = reply::stock_reply(reply::bad_request);
						do_write();
					}
					else
					{
						v_data.clear();
						do_read();
					}
				}
				else if (ec != boost::asio::error::operation_aborted)
				{
					v_data.clear();
					connection_manager_.stop(shared_from_this());
				}
			});
		}

第三处更改返回报文函数,在request_handler.cpp中的handle_request函数:

在这里插入图片描述

void request_handler::handle_request(const request& req, reply& rep)
{
  // Decode url to path.
  std::string request_path;
  if (!url_decode(req.uri, request_path))
  {
    rep = reply::stock_reply(reply::bad_request);
    return;
  }

  // Request path must be absolute and not contain "..".
  if (request_path.empty() || request_path[0] != '/'
      || request_path.find("..") != std::string::npos)
  {
    rep = reply::stock_reply(reply::bad_request);
    return;
  }


  // Fill out the reply to be sent to the client.
  rep.status = reply::ok;

  // 5 发送返回数据
  //返回响应头
  rep.headers.resize(1);
  rep.headers[0].name = "Content-Length";
  rep.headers[0].value = std::to_string(rep.content.size());

  //返回响应体
  //处理接收的数据为req.body
  cout <<"请求体:"<< req.body << endl;
  string sendStr = "huanhuncao";
  rep.content.append(sendStr.c_str(), sendStr.length());

  
}

只需要更改以上三个地方,这个HTTP服务就可以接收post请求的数据了,运行这个程序,然后用fiddler发送一些post请求。
在这里插入图片描述
在这里插入图片描述
可以看到,成功接收的post请求的请求体数据。
工程代码放到github上了,下载地址如下:
https://github.com/yuxuepiaoxi/asio_test

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Keras深度学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值