c++ 实现http get 和 post

Posted qianbo_insist

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++ 实现http get 和 post相关的知识,希望对你有一定的参考价值。

实现http协议

使用boost asio 去实现client,代码比较简单,熟悉http协议就行,这样得好处是至少不用包含很多第三方库,且也可以使用asio 直接实现。这个我已经实验过了,没有问题

#pragma once
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <boost/asio.hpp>
#include <vector>
using namespace boost;
using asio::ip::tcp;
using std::string;

//这里直接搜索http的头部字符串

static size_t split_httphead(const std::string str, std::string &k, std::string &v)

	size_t pos = -1;
	for (size_t i = 0; i < str.size(); i++)
	
		if (str[i] == ':')
		
			pos = i;
			break;
		
	
	if (pos != -1)
	

		k = str.substr(0, pos);
		while (str[pos++] == ' ');
		v = str.substr(pos + 1);
		v.pop_back();//remove \\r
	
	return pos;


int get_host_port_route(const char *url, char *host, uint16_t &port, char *route)

	char tmp[256];
	char *pos = (char*)url;
	int start = 7;
	if (*(pos + 4) == ':')
		pos += 7;
	else if ((*pos + 5) == ':')
	
		pos += 8;
		start = 8;
	
	else
		return -1;
	const char *end = url + strlen(url);
	for (; pos < end; pos++)
	
		if (*pos == '/')
		
			size_t l1 = pos - url;
			strncpy(tmp, url, l1);
			tmp[l1] = '\\0';
			size_t l2 = end - pos;
			strncpy(route, pos, l2);
			route[l2] = '\\0';
			break;
		
	
	//分解b1 到 host 和port
	pos = &tmp[start];
	int myport = 80;
	std::sscanf(pos, "%[^:/]:%d", host, &myport);
	port = myport;
	return 0;


//以下是post
static int http_post(const string& host, const string& port, const string& page, const string& data, string& reponse_data)

	try
	
		asio::io_service io_service;
		//如果io_service存在复用的情况
		if (io_service.stopped())
			io_service.reset();

		// 从dns取得域名下的所有ip
		tcp::resolver resolver(io_service);
		tcp::resolver::query query(host, port);
		tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

		// 尝试连接到其中的某个ip直到成功 
		tcp::socket socket(io_service);
		asio::connect(socket, endpoint_iterator);

		// Form the request. We specify the "Connection: close" header so that the
		// server will close the socket after transmitting the response. This will
		// allow us to treat all data up until the EOF as the content.
		asio::streambuf request;
		std::ostream request_stream(&request);
		request_stream << "POST " << page << " HTTP/1.0\\r\\n";
		request_stream << "Host: " << host << ":" << port << "\\r\\n";
		request_stream << "Accept: */*\\r\\n";
		request_stream << "Content-Length: " << data.length() << "\\r\\n";
		request_stream << "Content-Type: application/x-www-form-urlencoded\\r\\n";
		request_stream << "Connection: close\\r\\n\\r\\n";
		request_stream << data;

		// Send the request.
		asio::write(socket, request);

		// Read the response status line. The response streambuf will automatically
		// grow to accommodate the entire line. The growth may be limited by passing
		// a maximum size to the streambuf constructor.
		asio::streambuf response;
		asio::read_until(socket, response, "\\r\\n");

		// Check that response is OK.
		std::istream response_stream(&response);
		std::string http_version;
		response_stream >> http_version;
		unsigned int status_code;
		response_stream >> status_code;
		std::string status_message;
		std::getline(response_stream, status_message);
		if (!response_stream || http_version.substr(0, 5) != "HTTP/")
		
			reponse_data = "Invalid response";
			return -2;
		
		// 如果服务器返回非200都认为有错,不支持301/302等跳转
		if (status_code != 200)
		
			reponse_data = "Response returned with status code != 200 ";
			return status_code;
		

		// 传说中的包头可以读下来了
		std::string header;
		std::vector<string> headers;
		while (std::getline(response_stream, header) && header != "\\r")
			headers.push_back(header);

		// 读取所有剩下的数据作为包体

		boost::system::error_code error;
		//asio::error_code error;
		while (boost::asio::read(socket, response,
			asio::transfer_at_least(1), error))
		
		

		//响应有数据
		if (response.size())
		
			std::istream response_stream(&response);
			std::istreambuf_iterator<char> eos;
			reponse_data = string(std::istreambuf_iterator<char>(response_stream), eos);
		

		if (error != asio::error::eof)
		
			reponse_data = error.message();
			return -3;
		
	
	catch (std::exception& e)
	
		reponse_data = e.what();
		return -4;
	
	return 0;





static size_t http_get(const string& host, 
	const string& port, 
	const string& page, 
	string& lines)

	asio::io_context io_context;
	//如果io_service存在复用的情况
	//if (io_service.stopped())
	//	io_service.reset();

	// 从dns取得域名下的所有ip
	tcp::resolver resolver(io_context);
	tcp::resolver::query query(host, port);
	tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

	// 尝试连接到其中的某个ip直到成功 
	tcp::socket socket(io_context);
	asio::connect(socket, endpoint_iterator);
	asio::streambuf request;
	std::ostream request_stream(&request);
	request_stream << "GET " << page << " HTTP/1.0\\r\\n";
	request_stream << "Host: " << host << "\\r\\n";
	request_stream << "Accept: */*\\r\\n";
	request_stream << "User-Agent: MST browser/1.1.1\\r\\n";
	request_stream << "Connection: close\\r\\n\\r\\n";

	// Send the request.
	asio::write(socket, request);

	// Read the response status line. The response streambuf will automatically
	// grow to accommodate the entire line. The growth may be limited by passing
	// a maximum size to the streambuf constructor.
	asio::streambuf response;
	//asio::async_read_until()
	asio::read_until(socket, response, "\\r\\n\\r\\n");

	//Check that response is OK.
	std::istream response_stream(&response);
	std::string http_version;
	response_stream >> http_version;
	unsigned int status_code;
	response_stream >> status_code;
	std::string status_message;
	std::getline(response_stream, status_message);
	if (!response_stream || http_version.substr(0, 5) != "HTTP/")
	
		std::cout << "Invalid response";
		return -1;
	

	if (status_code != 200)
	
		std::cout << "Response returned with status code != 200 ";
		return -1;
		//return status_code;
	

	size_t len = 0;
	std::string header;
	std::vector<string> headers;
	while (std::getline(response_stream, header) && header != "\\r")
		headers.push_back(header);
	for (size_t i = 0; i < headers.size(); i++)
	
		//std::cout << headers[i] << std::endl;
		std::string k, v;

		if (split_httphead(headers[i], k, v) > 0)
		
			//std::cout << k << "->" << v << std::endl;
			if (k.compare("Content-Length") == 0)
			
				len = std::atoi(v.c_str());
				break;
			
		
	

	if (len <= 0)
		return -1;
//	buff.resize(len);

	///
	//asio::error_code error;
	boost::system::error_code error;
#if 1
	while (asio::read(socket,
		response,
		asio::transfer_at_least(1), 
		error));
	if (response.size())
	
		len = response.size();
		//buff.resize(response.size());
		//uint8_t * buffer = new uint8_t[len];


		asio::streambuf::const_buffers_type bufs = response.data();
		lines = string(asio::buffers_begin(bufs), asio::buffers_begin(bufs) + len);
		//std::string lines(asio::buffers_begin(bufs), asio::buffers_begin(bufs) + len);
		//cout << lines << endl;

		//response.sgetn((char*)&buff[0], len);
		//return length;
		//std::istream response_stream(&response);
		//std::istreambuf_iterator<char> eos;
		//reponse_data = string(std::istreambuf_iterator<char>(response_stream), eos);
	
#endif
#if 0
	uint8_t *pbuff = &(buff[0]);
	asio::read(socket, asio::buffer(pbuff, len),error);


#endif
	//string reponse_data;
	//响应有数据
	

	if (error != asio::error::eof)
	
		//reponse_data = error.message();
		return -1;
	
	return len;

以上是关于c++ 实现http get 和 post的主要内容,如果未能解决你的问题,请参考以下文章

[C++][原创]ubuntu上C++发送http请求get和post

C++通过HTTP请求Get或Post方式请求Json数据(转)

php之curl实现http请求(支持GET和POST)

golang原生api实现get和post

在LINUX下如何利用C语言实现HTTP的get和post方法?

一个简单的http server,处理get和post请求,Python实现