引言
http协议是互联网上应用最为广泛的一种网络协议,他在接口中扮演着重要的角色,Post/Get请求,想必大家都有所耳闻,我们一起利用Boost::Asio库来实现Post/Get请求的发送。
注意:本篇代码没有直接引用boost等命名空间,为的是新入门Boost的同学能够更好的了解每个参数在boost的具体命名空间位置,有助于更好的理解boost的布局。
版权所有:CSND_Ayo
,转载请注明出处:
http://blog.csdn.net/csnd_ayo
简介
Boost库版本:1.61.0
http请求:想必大家早已经耳濡目染,我这里就不做太多赘述,附上一个图片,以便大家加深印象。
下载
我封装了下,含代码,样例程序,动态库,资源下载地址:http://download.csdn.net/detail/csnd_ayo/9792036
BOOST库1.63:https://sourceforge.net/projects/boost/files/boost/1.63.0/boost_1_63_0.zip/download
赏析
暂无
源码
完成这个实现分别建立了2个类来解决这个实现。
HttpBase,HttpBoost。以达到抽象的效果。
http_mark.h 错误宏
example.cpp 示例调用文件
post 请求发送方式: 协议url[表数据]
get 请求发送方式:协议url
http_mark.h
#ifndef __CLY_HTTP_MARK_H__
#define __CLY_HTTP_MARK_H__
#define HTTP_SUCCESS (0) // 操作成功
#define HTTP_ERROR_UNKNOWN (-1) // 未知的错误
#define HTTP_ERROR_NETWORK (-2) // 网络连接失败
#define HTTP_ERROR_HTTP_HEAD (-3) // 未找到协议头 http || https
#define HTTP_ERROR_SERVICE (-1000) // 服务器请求失败
#define HTTP_ERROR_LOGIN (-1001) // 登录失败
#define HTTP_ERROR_ID (-1002) // 企业ID错误
#define HTTP_ERROR_USER (-1003) // 帐号不存在
#define HTTP_ERROR_PASSWORD (-1004) // 密码错误
#endif // __CLY_HTTP_MARK_H__
HttpBase.h
/*
* 简介:利用Boost发送http的Post/Get请求
* 作者:Louie
* 邮箱:727057301@qq.com
* CSDN:http://blog.csdn.net/csnd_ayo
* 码云:https://git.oschina.net/Mr_ChenLuYong
* github:http://github.com/chenluyong
* 创建时间:2017年3月12日 04:32:07
* VS版本:VS2013
* Boost版本:boost_1_61_0
*/
#ifndef __CLY_HTTPBASE_H__
#define __CLY_HTTPBASE_H__
#include <iostream>
using namespace std;
namespace cly {
class HttpBase {
public:
HttpBase();
virtual ~HttpBase();
/*
* 发送Post请求
*/
virtual int post(const std::string& url) = 0;
/*
* 发送get请求
*/
virtual int get(const std::string& url) = 0;
virtual std::string getResponse(void) = 0;
protected:
typedef int(*pBuildRequest)(const string&, const string&,
std::ostream&);
/*
* 解析URL
* parseUrl
* url: 待解析的URL
* out_server: 服务器名
* out_port: 端口号
* out_path: 服务器子页
*/
static int parseUrl(const std::string& url, std::string& out_server,
std::string& out_port, std::string& out_path);
/*
* 建立Post请求
* buildPostRequest
*/
static int buildPostRequest(const std::string& server, const std::string& path,
std::ostream& out_request);
/*
* 建立Get请求
* buildGetRequest
*/
static int buildGetRequest(const std::string& server, const std::string& path,
std::ostream& out_request);
};
}
#endif // __CLY_HTTPBASE_H__
HttpBase.cpp
/*
* 简介:利用Boost发送http的Post/Get请求
* 作者:Louie
* 邮箱:727057301@qq.com
* CSDN:http://blog.csdn.net/csnd_ayo
* 码云:https://git.oschina.net/Mr_ChenLuYong
* github:http://github.com/chenluyong
* 创建时间:2017年3月12日 04:32:07
* VS版本:VS2013
* Boost版本:boost_1_61_0
*/
#include "HttpBase.h"
#include "http_mark.h"
#define HTTP_JSON_BEGIN ("[")
#define HTTP_JSON_END ("]")
using namespace cly;
cly::HttpBase::HttpBase() {
}
cly::HttpBase::~HttpBase() {
}
//
//可以解析下列三种类型的URL:
//http://yunhq.sse.com.cn:32041/v1/sh1/snap/204001?callback=jQuery_test&select=name%2Clast%2Cchg_rate%2Cchange%2Camount%2Cvolume%2Copen%2Cprev_close%2Cask%2Cbid%2Chigh%2Clow%2Ctradephase
//http://hq.sinajs.cn/list=sh204001
//https://www.baidu.com
//
int cly::HttpBase::parseUrl(const std::string& url, std::string& out_server,
std::string& out_port, std::string& out_path) {
const std::string& http___ = "http://";
const std::string& https___ = "https://";
std::string temp_data = url;
// 截断http协议头
if (temp_data.find(http___) == 0) {
temp_data = temp_data.substr(http___.length());
}
else if (temp_data.find(https___) == 0) {
temp_data = temp_data.substr(https___.length());
}
else {
return HTTP_ERROR_HTTP_HEAD;
}
// 解析域名
std::size_t idx = temp_data.find('/');
// 解析 域名后的page
if (std::string::npos == idx) {
out_path = "/";
idx = temp_data.size();
}
else {
out_path = temp_data.substr(idx);
}
// 解析域名
out_server = temp_data.substr(0, idx);
// 解析端口
idx = out_server.find(':');
if (std::string::npos == idx) {
out_port = "80";
}
else {
out_port = out_server.substr(idx + 1);
out_server = out_server.substr(0, idx);
}
return HTTP_SUCCESS;
}
/*
* 建立Post请求
* buildPostRequest
*/
int cly::HttpBase::buildPostRequest(const std::string& server, const std::string& path,
std::ostream& out_request) {
// 分割path中的json数据
std::string temp_path(path), temp_json;
int json_pos_begin = temp_path.find(HTTP_JSON_BEGIN) + 1;
int json_pos_end = temp_path.find(HTTP_JSON_END);
if (json_pos_begin != std::string::npos) {
// 计算json的长度
int temp_json_lenth = std::string::npos;
if (json_pos_end != temp_json_lenth) {
temp_json_lenth = (json_pos_end - json_pos_begin);
}
temp_json = temp_path.substr(json_pos_begin, temp_json_lenth);
temp_path = temp_path.substr(0, (json_pos_begin - 1));
}
out_request << "POST " << temp_path.c_str() << " HTTP/1.0\r\n";
out_request << "Host: " << server.c_str() << "\r\n";
out_request << "Content-Length: " << temp_json.length() << "\r\n";
out_request << "Content-Type: application/x-www-form-urlencoded\r\n";
out_request << "Accept: */*\r\n";
out_request << "Connection: close\r\n\r\n";
out_request << temp_json.c_str();
return HTTP_SUCCESS;
}
/*
* 建立Get请求
* buildGetRequest
*/
int cly::HttpBase::buildGetRequest(const std::string& server, const std::string& path,
std::ostream& out_request) {
out_request << "GET " << path.c_str() << " HTTP/1.0\r\n";
out_request << "Host: " << server.c_str() << "\r\n";
out_request << "Accept: */*\r\n";
out_request << "Connection: close\r\n\r\n";
return HTTP_SUCCESS;
}
HttpBoost.h
/*
* 简介:利用Boost发送http的Post/Get请求
* 作者:Louie
* 邮箱:727057301@qq.com
* CSDN:http://blog.csdn.net/csnd_ayo
* 码云:https://git.oschina.net/Mr_ChenLuYong
* github:http://github.com/chenluyong
* 创建时间:2017年3月12日 04:32:07
* VS版本:VS2013
* Boost版本:boost_1_61_0
*/
#ifndef __CLY_HTTPBOOST_H__
#define __CLY_HTTPBOOST_H__
#include "HttpBase.h"
#include <boost/asio.hpp>
namespace cly {
class HttpBoost :
public HttpBase {
public:
HttpBoost(boost::asio::io_service& io_service);
virtual ~HttpBoost();
/*
* 发送Post请求
*/
virtual int post(const std::string& url);
/*
* 发送get请求
*/
virtual int get(const std::string& url);
virtual std::string getResponse(void) {
return responseData_;
}
private:
// 建立请求
void handle_request_resolve(const std::string& url, pBuildRequest func);
// 解析后
void handle_resolve(const boost::system::error_code& err,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator);
// 连接后
void handle_connect(const boost::system::error_code& err);
// 发送请求后
void handle_write_request(const boost::system::error_code& err);
// 读取响应后
void handle_read_status_line(const boost::system::error_code& err);
// 读取响应头后
void handle_read_headers(const boost::system::error_code& err);
// 读取正文数据后
void handle_read_content(const boost::system::error_code& err);
private:
// 解析器
boost::asio::ip::tcp::resolver resolver_;
// 套接字
boost::asio::ip::tcp::socket socket_;
// 请求缓冲区
boost::asio::streambuf request_;
// 响应缓冲区
boost::asio::streambuf response_;
// 响应数据
std::string responseData_;
};
// Post请求 消息范例 url:80/openapi/getversion[Post请求数据表格]
std::string post(std::string url);
std::string get(std::string url);
}
#endif // __CLY_HTTPBOOST_H__
HttpBoost.cpp
/*
* 简介:利用Boost发送http的Post/Get请求
* 作者:Louie
* 邮箱:727057301@qq.com
* CSDN:http://blog.csdn.net/csnd_ayo
* 码云:https://git.oschina.net/Mr_ChenLuYong
* github:http://github.com/chenluyong
* 创建时间:2017年3月12日 04:32:07
* VS版本:VS2013
* Boost版本:boost_1_61_0
*/
#include "HttpBoost.h"
using namespace cly;
#include <boost/bind.hpp>
#include "http_mark.h"
cly::HttpBoost::HttpBoost(boost::asio::io_service& io_service)
: resolver_(io_service), socket_(io_service) {
}
cly::HttpBoost::~HttpBoost() {
}
int cly::HttpBoost::post(const std::string& url) {
handle_request_resolve(url, HttpBase::buildPostRequest);
return HTTP_SUCCESS;
}
int cly::HttpBoost::get(const std::string& url) {
handle_request_resolve(url, HttpBase::buildGetRequest);
return HTTP_SUCCESS;
}
void cly::HttpBoost::handle_request_resolve(const std::string& url, pBuildRequest func) {
try {
responseData_.clear();
// 解析URL
std::string server, port, path;
parseUrl(url, server, port, path);
std::ostream request_stream(&request_);
// 合成请求
func(server, path, request_stream);
// 解析服务地址\端口
boost::asio::ip::tcp::resolver::query query(server, port);
resolver_.async_resolve(query,
boost::bind(&cly::HttpBoost::handle_resolve, this,
boost::asio::placeholders::error,
boost::asio::placeholders::iterator));
}
catch (std::exception& e) {
socket_.close();
std::cout << "Exception: " << e.what() << "\n";
}
return;
}
void cly::HttpBoost::handle_resolve(const boost::system::error_code& err,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator) {
if (err) {
std::cout << "Error: " << err << "\n";
return;
}
// 尝试连接
boost::asio::async_connect(socket_, endpoint_iterator,
boost::bind(&cly::HttpBoost::handle_connect, this,
boost::asio::placeholders::error));
}
void cly::HttpBoost::handle_connect(const boost::system::error_code& err) {
if (err) {
std::cout << "Error: " << err << "\n";
return;
}
// 发送request请求
boost::asio::async_write(socket_, request_,
boost::bind(&cly::HttpBoost::handle_write_request, this,
boost::asio::placeholders::error));
}
void cly::HttpBoost::handle_write_request(const boost::system::error_code& err) {
if (err) {
std::cout << "Error: " << err << "\n";
return;
}
// 异步持续读数据到response_,直到接收协议符号 \r\n 为止
boost::asio::async_read_until(socket_, response_, "\r\n",
boost::bind(&cly::HttpBoost::handle_read_status_line, this,
boost::asio::placeholders::error));
}
void cly::HttpBoost::handle_read_status_line(const boost::system::error_code& err) {
if (err) {
std::cout << "Error: " << err << "\n";
return;
}
// 解析buff
std::istream response_stream(&response_);
unsigned int status_code;
std::string http_version, status_message;
response_stream >> http_version;
response_stream >> status_code;
std::getline(response_stream, status_message);
// 核对是否是正确返回
if (!response_stream || http_version.substr(0, 5) != "HTTP/") {
std::cout << "错误的响应数据\n";
return;
}
if (status_code != 200) {
std::cout << "服务器响应的状态码: " << status_code << "\n";
return;
}
// 读取响应头,直到接收协议符号 \r\n\r\n 为止
boost::asio::async_read_until(socket_, response_, "\r\n\r\n",
boost::bind(&cly::HttpBoost::handle_read_headers, this,
boost::asio::placeholders::error));
}
void cly::HttpBoost::handle_read_headers(const boost::system::error_code& err) {
if (err) {
std::cout << "Error: " << err << "\n";
return;
}
// 输出响应头
std::istream response_stream(&response_);
std::string header;
while (std::getline(response_stream, header) && header != "\r") {
#ifdef _DEBUG
std::cout << header << "\n";
#endif
}
#ifdef _DEBUG
std::cout << "\n";
#endif
// 写完所有剩余的内容
if (response_.size() > 0) {
boost::asio::streambuf::const_buffers_type cbt = response_.data();
responseData_ += std::string(boost::asio::buffers_begin(cbt), boost::asio::buffers_end(cbt));
#ifdef _DEBUG
std::cout << &response_;
#endif
}
// 开始读取剩余所有内容
boost::asio::async_read(socket_, response_,
boost::asio::transfer_at_least(1),
boost::bind(&cly::HttpBoost::handle_read_content, this,
boost::asio::placeholders::error));
}
void cly::HttpBoost::handle_read_content(const boost::system::error_code& err) {
if (!err) {
// 输出读到的数据
boost::asio::streambuf::const_buffers_type cbt = response_.data();
responseData_ += std::string(boost::asio::buffers_begin(cbt), boost::asio::buffers_end(cbt));
#ifdef _DEBUG
std::cout << &response_;
#endif
// 继续读取剩余内容,直到读到EOF
boost::asio::async_read(socket_, response_,
boost::asio::transfer_at_least(1),
boost::bind(&cly::HttpBoost::handle_read_content, this,
boost::asio::placeholders::error));
}
else if (err != boost::asio::error::eof) {
std::cout << "Error: " << err << "\n";
}
else {
socket_.close();
resolver_.cancel();
std::cout << "读取响应数据完毕." << std::endl;
}
}
std::string cly::post(std::string url) {
boost::asio::io_service io;
cly::HttpBoost c(io);
c.post(url);
io.run();
return c.getResponse();
}
std::string cly::get(std::string url) {
boost::asio::io_service io;
cly::HttpBoost c(io);
c.get(url);
io.run();
return c.getResponse();
}
example.cpp
#include <iostream>
#include "HttpBoost.h"
int main() {
std::string str("http://yunhq.sse.com.cn:32041/v1/sh1/snap/204001?callback=jQuery_test&select=name%2Clast%2Cchg_rate%2Cchange%2Camount%2Cvolume%2Copen%2Cprev_close%2Cask%2Cbid%2Chigh%2Clow%2Ctradephase");
str = cly::get(str);
std::cout << str.c_str() << std::endl;
str = "http://service.winic.org:8009/sys_port/gateway/[id=13695800360&pwd=13645411460&to=13695800360&content=infomation&time=]";
str = cly::post(str);
std::cout << str.c_str() << std::endl;
return 0;
}
代码中理论上是跨平台的。
详解
评论超过5个,我便会修改该文章,对整体思路进行梳理讲解。