目录
1.基于asio2实现的http示例代码
2.修改服务线程数
3.在绑定的路由请求中获取请求的远程的IP和端口
4.静态资源绑定
5.在 url 中传递参数的原理
5.1.简介
5.2.浏览器本地预处理(输入 URL 后,发请求前)
5.3.建立 TCP 连接
5.4.浏览器发送 HTTP 请求报文
5.5.服务端(asio2)接收、解析、处理请求
5.6.服务端返回 HTTP 响应报文
5.7.浏览器接收响应,解析渲染页面
5.8.连接维持与关闭
5.9.服务端把参数传给前端的两种方式
6.唯一标识用户还是需要token
7.跨域处理
8.QtWebEngine 拼接 URL 携带 Token
9.asio2 内置 URL 工具(http 命名空间)
Asio2: 一个基于 Boost.Asio 封装的高性能网络编程库(一)
1.基于asio2实现的http示例代码
源码如下:
#include <iostream> #include <asio2/asio2.hpp> struct aop_log { bool before(http::web_request& req, http::web_response& rep) { asio2::ignore_unused(rep); printf("aop_log before %s\n", req.method_string().data()); return true; } bool after(std::shared_ptr<asio2::http_session>& session_ptr, http::web_request& req, http::web_response& rep) { ASIO2_ASSERT(asio2::get_current_caller<std::shared_ptr<asio2::http_session>>().get() == session_ptr.get()); asio2::ignore_unused(session_ptr, req, rep); printf("aop_log after\n"); return true; } }; struct aop_check { bool before(std::shared_ptr<asio2::http_session>& session_ptr, http::web_request& req, http::web_response& rep) { ASIO2_ASSERT(asio2::get_current_caller<std::shared_ptr<asio2::http_session>>().get() == session_ptr.get()); asio2::ignore_unused(session_ptr, req, rep); printf("aop_check before\n"); return true; } bool after(http::web_request& req, http::web_response& rep) { asio2::ignore_unused(req, rep); printf("aop_check after\n"); return true; } }; int main() { // try open http://localhost:8080 in your browser std::string_view host = "0.0.0.0"; std::string_view port = "8080"; asio2::http_server server; server.support_websocket(true); // root = /asio2/bin/x64 std::filesystem::path root = std::filesystem::current_path(); // root = /asio2/example/wwwroot root = root.parent_path().parent_path().append("example/wwwroot"); // set the http server root directory server.set_root_directory(std::move(root)); server.bind_recv([&](http::web_request& req, http::web_response& rep) { asio2::ignore_unused(req, rep); // all http and websocket request will goto here first. std::cout << req.path() << req.query() << std::endl; }).bind_connect([](auto & session_ptr) { printf("client enter : %s %u %s %u\n", session_ptr->remote_address().c_str(), session_ptr->remote_port(), session_ptr->local_address().c_str(), session_ptr->local_port()); //session_ptr->set_response_mode(asio2::response_mode::manual); session_ptr->set_disconnect_timeout(std::chrono::seconds(2)); }).bind_disconnect([](auto & session_ptr) { printf("client leave : %s %u %s\n", session_ptr->remote_address().c_str(), session_ptr->remote_port(), asio2::last_error_msg().c_str()); }).bind_start([&]() { printf("start http server : %s %u %d %s\n", server.listen_address().c_str(), server.listen_port(), asio2::last_error_val(), asio2::last_error_msg().c_str()); }).bind_stop([&]() { printf("stop http server : %d %s\n", asio2::last_error_val(), asio2::last_error_msg().c_str()); }); server.bind<http::verb::get, http::verb::post>("/", [](http::web_request& req, http::web_response& rep) { asio2::ignore_unused(req, rep); rep.fill_file("/index.html"); }, aop_log{}, http::enable_cache); // If no method is specified, GET and POST are both enabled by default. server.bind("*", [](http::web_request& req, http::web_response& rep) { rep.fill_file(http::url_decode(req.target())); rep.chunked(true); }, aop_check{}, http::enable_cache); // Test http multipart server.bind<http::verb::get, http::verb::post>("/multipart_test", [](http::web_request& req, http::web_response& rep) { auto& body = req.body(); auto target = req.target(); std::stringstream ss; ss << req; auto str_req = ss.str(); asio2::ignore_unused(body, target, str_req); for (auto it = req.begin(); it != req.end(); ++it) { std::cout << it->name_string() << ": " << it->value() << std::endl; } auto mpbody = req.multipart(); for (auto it = mpbody.begin(); it != mpbody.end(); ++it) { std::cout << "filename:" << it->filename() << " name:" << it->name() << " content_type:" << it->content_type() << std::endl; } if (req.has_multipart()) { http::multipart_fields multipart_body = req.multipart(); auto& field_username = multipart_body["username"]; auto username = field_username.value(); auto& field_password = multipart_body["password"]; auto password = field_password.value(); std::string str = http::to_string(multipart_body); std::string type = "multipart/form-data; boundary="; type += multipart_body.boundary(); rep.fill_text(str, http::status::ok, type); http::web_request req_copy; req_copy.method(http::verb::post); req_copy.set(http::field::content_type, type); req_copy.keep_alive(true); req_copy.target("/api/user/"); req_copy.body() = str; req_copy.prepare_payload(); std::stringstream ress; ress << req_copy; auto restr = ress.str(); asio2::ignore_unused(username, password, restr); } else { rep.fill_page(http::status::ok); } }, aop_log{}); server.bind<http::verb::get>("/del_user", [](std::shared_ptr<asio2::http_session>& session_ptr, http::web_request& req, http::web_response& rep) { asio2::ignore_unused(req, rep); printf("del_user ip : %s\n", session_ptr->remote_address().data()); rep.fill_page(http::status::ok, "del_user successed."); }, aop_check{}); server.bind<http::verb::get, http::verb::post>("/api/user/*", [](http::web_request& req, http::web_response& rep) { asio2::ignore_unused(req, rep); // if the url is : // /api/user/add_user?name=hanmeimei&age=20&height=168 [[maybe_unused]] std::string_view t = req.target(); // t == /api/user/add_user?name=hanmeimei&age=20&height=168 [[maybe_unused]] std::string_view p = req.get_path(); // p == /api/user/add_user [[maybe_unused]] std::string_view q = req.get_query(); // q == name=hanmeimei&age=20&height=168 std::vector<std::string_view> kvs = asio2::split(q, '&'); for (std::string_view kv : kvs) { [[maybe_unused]] std::string_view k = kv.substr(0, kv.find('=')); [[maybe_unused]] std::string_view v = kv.substr(kv.find('=') + 1); } //rep.fill_text("the user name is hanmeimei, ....."); }, aop_log{}, aop_check{}); server.bind<http::verb::get>("/defer", [](http::web_request& req, http::web_response& rep) { asio2::ignore_unused(req, rep); // use defer to make the reponse not send immediately, util the derfer shared_ptr // is destroyed, then the response will be sent. std::shared_ptr<http::response_defer> rep_defer = rep.defer(); std::thread([rep_defer, &rep]() mutable { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); rep = asio2::http_client::execute("http://www.baidu.com"); }).detach(); }, aop_log{}, aop_check{}); // the /ws is the websocket upgraged target server.bind("/ws", websocket::listener<asio2::http_session>{}. on("message", [](std::shared_ptr<asio2::http_session>& session_ptr, std::string_view data) { printf("ws msg : %zu %.*s\n", data.size(), (int)data.size(), data.data()); session_ptr->async_send(data); }).on("open", [](std::shared_ptr<asio2::http_session>& session_ptr) { printf("ws open\n"); // print the websocket request header. std::cout << session_ptr->request() << std::endl; // same as above auto& req = session_ptr->get_request(); std::cout << req.get_path() << std::endl; // Set the binary message write option. session_ptr->ws_stream().binary(true); // Set the text message write option. //session_ptr->ws_stream().text(true); // how to set custom websocket response data : session_ptr->ws_stream().set_option(websocket::stream_base::decorator( [](websocket::response_type& rep) { rep.set(http::field::authorization, " http-server-coro"); })); // how to send a message to client when the websocket connection is connected. // can't use session_ptr->async_send(...) directly, because the websocket connection is not ready. session_ptr->post_queued_event([session_ptr]() { session_ptr->async_send("eg: hello websocket"); }); }).on("close", [](std::shared_ptr<asio2::http_session>& session_ptr) { asio2::ignore_unused(session_ptr); printf("ws close\n"); }).on_ping([](std::shared_ptr<asio2::http_session>& session_ptr) { asio2::ignore_unused(session_ptr); printf("ws ping\n"); }).on_pong([](std::shared_ptr<asio2::http_session>& session_ptr) { asio2::ignore_unused(session_ptr); printf("ws pong\n"); })); server.bind_not_found([](http::web_request& req, http::web_response& rep) { asio2::ignore_unused(req); rep.fill_page(http::status::not_found); }); server.start(host, port); while (std::getchar() != '\n'); // press enter to exit this program return 0; }2.修改服务线程数
如果不人为控制,asio2内部会自动获取系统的CPU核数,启动对于核数的线程,如果控制启动的线程数,可以手动传入参数,如:
asio2::http_server server(1); //1个线程http客户端(如浏览器)发送请求是并发的,服务端多线程处理,就会涉及到并发的去访问文件、数据库、网络等资源,设计的时候需要考虑到。
3.在绑定的路由请求中获取请求的远程的IP和端口
server.bind<http::verb::get, http::verb::post>("/", [](http::web_request& req, http::web_response& rep) { asio2::ignore_unused(req, rep); rep.fill_file("/index.html"); }, aop_log{}, http::enable_cache);在 asio2 库中,不能直接从http::web_request对象获取远端的 IP 和端口。http::web_request只封装了 HTTP 请求本身的内容(如方法、路径、头部等),不包含底层连接信息。
asio2 在绑定 HTTP 路由回调时,允许将会话对象指针(std::shared_ptr<asio2::http_session>)作为第一个参数传入。你需要通过这个会话对象来获取远端地址和端口。
server.bind<http::verb::get>("/", [](std::shared_ptr<asio2::http_session>& session_ptr, http::web_request& req, http::web_response& rep) { // 获取远端 IP 和端口 std::string remote_ip = session_ptr->remote_address(); uint16_t remote_port = session_ptr->remote_port(); printf("client ip: %s, port: %u\n", remote_ip.c_str(), remote_port); rep.fill_page(http::status::ok, "success"); }, aop_check{});关键点说明:
session_ptr是回调的第一个参数:asio2 允许你在 HTTP 回调签名中选择是否添加这个参数。如果不需要远端信息,可以省略它;如果需要,就把它加上。remote_address()返回std::string_view:可以直接.data()或转换为std::string使用。remote_port()返回端口号:类型通常为uint16_t。
4.静态资源绑定
// If no method is specified, GET and POST are both enabled by default. server.bind("*", [](http::web_request& req, http::web_response& rep) { rep.fill_file(http::url_decode(req.target())); rep.chunked(true); }, aop_check{}, http::enable_cache);| req的路径函数 | 对应含义 |
|---|---|
req.path() | 服务器切开?后得到的路径部分 |
req.query() | 服务器切开?后得到的原始参数字符串 |
| req.target() | 完整原始请求目标(path + ? + query) |
| req.body() | body内容 |
parse_query(raw_q) | 按&分割、按=拆键值、执行 URL 解码 |
rep.fill_file(req.path()) | 只用 path 拼接 root_dir 找文件,query 完全不参与 |
// 完整原始target std::string full_target = req.target();//如:/index.html?a=10&b=10 // 拆分好的路径 std::string path = req.path(); //如:/index.html // 拆分好的查询串 std::string query_raw = req.query();//如:a=10&b=10如果在主目录下有个index.html,那么就可以通过下面的地址访问:
http://192.168.3.62:8080/index.html
5.在 url 中传递参数的原理
5.1.简介
基于RFC 3986 URI 标准和 HTTP 协议规范,URL 参数(Query String)本质是在请求行中附加的键值对信息,和资源路径严格分离,全程不影响服务端文件定位。
一个完整 HTTP URL 的结构如下,?是路径和参数的法定分隔符:
http://127.0.0.1:8080/index.html?uid=1001&name=张三#section └──┬───┘ └────┬────┘ └──┬───┘ └────────┬────────┘ └──┬───┘ 协议 主机:端口 路径 查询参数 锚点(fragment)| 部分 | 作用 | 是否发给服务端 |
|---|---|---|
路径/index.html | 定位服务器上的资源 / 路由 | 是 |
查询参数uid=1001&name=张三 | 传递业务参数 | 是 |
锚点#section | 浏览器内页面定位 | 否,完全不发给服务器 |
核心结论:服务器解析 URL 时,会在第一个
?处直接切开,前面的部分作为资源路径,后面的部分作为纯参数字符串。 这就是你之前观察到的「asio2 自动分开 path 和 query」的底层原因 —— 所有标准 HTTP 服务器都是这么实现的。
整个过程是「浏览器封装编码 → 网络传输 → 服务端解析处理 → 网络返回 → 浏览器解析渲染」的完整闭环,底层基于 TCP/IP 协议栈和 HTTP 应用层协议。
5.2.浏览器本地预处理(输入 URL 后,发请求前)
用户在地址栏输入 URL 并回车,浏览器先做 4 件事:
1. 拆分 URL 结构
按标准把 URL 拆成独立字段,?是路径和参数的法定分界符
协议: http 主机: 127.0.0.1 端口: 8080 路径: /index.html 查询参数: uid=1001&name=张三&token=abc1232.URL 编码(百分号编码)
URL 只允许 ASCII 字符,中文、空格、特殊符号会自动编码:
张三→%E5%BC%A0%E4%B8%89- 空格 →
%20 - 目的:避免中文乱码、避免特殊字符(如
&、=)破坏参数结构
对应你代码里的
url_decode,就是做这个的逆过程。
3. 缓存检查
浏览器先查本地缓存(强缓存 / 协商缓存),如果页面之前访问过且没过期,直接从本地加载,不发请求到服务器。
4. DNS 解析(域名转 IP)
如果是域名(如www.test.com),浏览器会通过 DNS 服务器把域名解析成 IP 地址; 你用127.0.0.1是本地回环地址,直接跳过 DNS 解析。
5.3.建立 TCP 连接
HTTP 基于 TCP 传输,浏览器和服务器通过TCP 三次握手建立可靠连接:
- 浏览器 → 服务器:SYN 同步包
- 服务器 → 浏览器:SYN+ACK 确认包
- 浏览器 → 服务器:ACK 确认包
连接建立后,才能开始传输 HTTP 报文。 如果是 HTTPS,这一步还会额外做 TLS 加密握手。
5.4.浏览器发送 HTTP 请求报文
连接建立后,浏览器把请求内容封装成标准 HTTP 报文,通过 TCP 发出去。
HTTP 请求报文结构
【请求行】GET /index.html?uid=1001&name=%E5%BC%A0%E4%B8%89&token=abc123 HTTP/1.1 【请求头】 Host: 127.0.0.1:8080 User-Agent: Chrome/120.0.0.0 Accept: text/html,application/xhtml+xml Connection: keep-alive ... 【空行】 【请求体】(GET 请求体为空,POST 才会放数据)核心要点
- 参数在请求行的 URL 里,不在请求体里:GET 请求的参数永远跟在路径后面,不会放进 body。
- 参数已经编码完成:
name=张三变成了name=%E5%BC%A0%E4%B8%89。 - 整个报文是纯文本格式,按行分隔。
5.5.服务端(asio2)接收、解析、处理请求
这是你写的 C++ 代码真正执行的阶段,asio2 内部按以下步骤执行:
步骤 1:接收并解析 HTTP 报文
asio2 从 TCP 连接读取数据,按 HTTP 协议解析出:
- 请求方法:
GET - 完整 URL:
/index.html?uid=1001&name=%E5%BC%A0%E4%B8%89&token=abc123 - 所有请求头
步骤 2:拆分路径和查询参数
在第一个?处直接切开,分成两部分存储:
req.path()→/index.html(只用来匹配路由、找文件)req.query()→uid=1001&name=%E5%BC%A0%E4%B8%89&token=abc123(纯参数字符串)
✅ 这就是「带参数也能正常访问静态文件」的根本原因:查询参数根本不参与文件路径拼接,找文件只用 path 部分。
步骤 3:路由匹配
asio2 按你写bind的从上到下顺序,用req.path()去匹配每个路由的正则:
- 先匹配
/api/echo等业务接口 → 不匹配 - 再匹配最后的
.*静态兜底路由 → 匹配成功,执行对应的回调函数
步骤 4:执行业务回调(你写的代码逻辑)
- 调用
parse_query(req.query()):按&分割、按=拆键值、做 URL 解码,得到参数 map - Token 校验:取出
token判断是否合法,不合法直接返回 401,终止流程 - 静态资源处理:
- 如果是
index.html:调用rep.load_file()读取 HTML 文件,把{{uid}}、{{name}}替换成参数值(服务端模板注入) - 如果是 css/js:调用
rep.fill_file()直接读取文件内容
- 如果是
- 设置 CORS 跨域响应头、Content-Type 等
步骤 5:构建 HTTP 响应报文
asio2 把处理结果封装成标准 HTTP 响应报文,包含:
- 状态行:
HTTP/1.1 200 OK - 响应头:
Content-Type、Access-Control-Allow-Origin等 - 响应体:处理后的 HTML 内容 / 文件二进制数据
5.6.服务端返回 HTTP 响应报文
asio2 把封装好的响应报文,通过 TCP 连接发回给浏览器。
HTTP 响应报文示例
【状态行】HTTP/1.1 200 OK 【响应头】 Content-Type: text/html;charset=utf-8 Content-Length: 1256 Access-Control-Allow-Origin: * Connection: keep-alive 【空行】 【响应体】 <!DOCTYPE html> <html>...(完整的HTML页面内容,占位符已经替换成实际参数值)5.7.浏览器接收响应,解析渲染页面
浏览器收到响应后,按以下步骤处理,最终显示出页面:
1. 解析响应
- 读取状态码:200 表示成功,404 表示找不到,401 表示未授权
- 读取响应头:根据
Content-Type判断内容类型 - 接收完整响应体
2. HTML 解析 → DOM 树
浏览器把 HTML 文本从上到下解析,构建 DOM(文档对象模型)树,页面上的每个标签都是树上的一个节点。
如果是服务端模板注入的参数(
{{uid}}),解析后直接就是实际值,页面上立刻能看到。
3. CSS 解析 → 渲染树
解析 CSS 样式,把 DOM 树和样式结合,生成渲染树,计算每个元素的位置、大小、颜色。
4. JS 执行
遇到<script>标签就暂停解析,执行 JS 代码:
- 如果是前端 JS 读取 URL 参数:JS 通过
window.location.search拿到地址栏里的 query 字符串,用URLSearchParams解析出 uid、name 等参数 - 如果有 fetch/axios 请求:JS 再发起新的 HTTP 请求去调用后端 API
5. 绘制与显示
浏览器根据渲染树,把页面像素绘制到屏幕上,用户最终看到完整的网页。
5.8.连接维持与关闭
- 默认开启
Connection: keep-alive长连接,同一个域名的后续请求复用这个 TCP 连接,不用每次都三次握手 - 连接空闲一段时间后,通过TCP 四次挥手关闭连接
5.9.服务端把参数传给前端的两种方式
| 方式 | 环节 | 原理 |
|---|---|---|
| 服务端模板注入 | 阶段 4 步骤 4 | asio2 读取 HTML 文件,把占位符替换成参数值,再返回给浏览器 |
| 前端 JS 读取 URL | 阶段 6 步骤 4 | 浏览器地址栏本身就带参数,JS 直接从window.location里解析 |
6.唯一标识用户还是需要token
token的主要作用是用来验证这个请求是「我的合法客户端」,拦截陌生 / 非法访问。还有一个重要作用是关联上下文。因为http客户端的请求是多线程多连接并发的,用远程的ip和端口来表示唯一用户是不科学的。
asio2中一般是在登陆请求处理后返回的http头添加token,后面访问其它接口,都必须加上token,解析出的token的方法:
http::web_request& req std::string token; for (auto it = req.begin(); it != req.end(); ++it) { std::cout << it->name_string() << ": " << it->value() << std::endl; if (it->name_string() == "Authorize"){ token = it->value(); } }7.跨域处理
asio2::http_server server; server.bind<asio2::http::verb::get>(".*", [](asio2::http_request &req, asio2::http_response &rep) { // 获取TCP远端IP和端口 std::string client_ip = req.remote_address(); uint16_t client_port = req.remote_port(); std::cout << "[访问] " << client_ip << ":" << client_port << " | " << req.path() << "?" << req.query() << "\n"; auto params = parse_query(req.query()); // ========== Token校验 ========== auto token_it = params.find("token"); if(token_it == params.end() || token_it->second != g_server_token) { rep.status(401); rep.set_header("Content-Type", "text/html;charset=utf-8"); rep.body() = "<h1>401 未授权,Token无效</h1>"; return; } // =============================== // CORS跨域头 rep.set("Access-Control-Allow-Origin", "*"); rep.set("Access-Control-Allow-Methods", "GET,POST,OPTIONS"); rep.set_hseteader("Access-Control-Allow-Headers", "*"); if(req.path() == "/index.html") { std::string html; if(rep.load_file(req.path(), html)) { std::string uid = params["uid"]; replace_all(html, "{{uid}}", uid); rep.body() = html; rep.set_header("Content-Type", "text/html;charset=utf-8"); } else { rep.status(404); rep.body() = "<h1>404 Not Found</h1>"; } } else { bool ok = rep.fill_file(req.path()); if(!ok) { rep.status(404); rep.body() = "<h1>404</h1>"; } } });8.QtWebEngine 拼接 URL 携带 Token
QUrl url("http://127.0.0.1:8080/index.html"); QUrlQuery query; query.addQueryItem("token", g_server_token); query.addQueryItem("uid", "1001"); url.setQuery(query); ui->webView->setUrl(url);9.asio2 内置 URL 工具(http 命名空间)
asio2 自带 http url 解析、编解码工具,直接分离 scheme/host/path/query,path、query 中文必须 url_encode,不支持裸中文直接请求:
#include "asio2/http.hpp" using namespace asio2; // 1. URL编解码(核心本地化:中文、特殊字符百分号编码 UTF-8) std::string raw_url = "http://127.0.0.1:8080/api/文件?name=测试"; std::string url_enc = http::url_encode(raw_url); std::string url_dec = http::url_decode(url_enc); // 2. 拆分path / query std::string path = http::url_to_path("/api/文件?name=测试"); std::string query = http::url_to_query("/api/文件?name=测试"); // 3. 直接http_client执行url asio2::http_client client; std::error_code ec; auto rep = client.execute("http://localhost:8080/hello", ec);接口说明
http::url_encode:RFC3986 百分号编码,路径、查询参数中文、空格、#& 等特殊字符用这个http::url_decode:解码url_to_path:提取路径(/xxx)url_to_query:提取?后的 query 串
注意:asio2没有内置 IDNA (Punycode) 域名编码。如果是中文域名
http://中文域名.com,需要自己实现 punycode 转码后再传给 asio2。
完整的示例如下:
#include <asio2/http/http_client.hpp> #include <iostream> int main() { std::string_view host = "127.0.0.1"; std::string_view port = "8080"; asio2::socks5::option<asio2::socks5::method::anonymous> sock5_option{ "127.0.0.1",10808 }; //asio2::socks5::option<asio2::socks5::method::anonymous, asio2::socks5::method::password> // sock5_option{ "s5.doudouip.cn",1088,"zjww-1","aaa123" }; // download and save the file directly. // see ssl_http_client.cpp // The file is in this directory: /asio2/example/bin/x64/100mb.test asio2::http_client::download("http://cachefly.cachefly.net/100mb.test", "100mb.test"); std::string_view url = R"(http://www.baidu.com/cond?json={"qeury":"name like '%abc%'","id":1})"; std::string en = http::url_encode(url); std::cout << en << std::endl; std::string de = http::url_decode(en); std::cout << de << std::endl; auto path = asio2::http::url_to_path(url); std::cout << path << std::endl; auto query = asio2::http::url_to_query(url); std::cout << query << std::endl; auto rep21 = asio2::http_client::execute(url); std::cout << rep21 << std::endl; http::web_request req24 = http::make_request(url); req24.set(http::field::user_agent, "Chrome"); auto rep26 = asio2::http_client::execute(req24); std::cout << rep26 << std::endl; asio2::http_client::execute("www.baidu.com", "80", "/", std::chrono::seconds(5)); asio2::http_client::execute("www.baidu.com", "80", "/", sock5_option); // GET auto req2 = http::make_request("GET / HTTP/1.1\r\nHost: 192.168.0.1\r\n\r\n"); auto rep2 = asio2::http_client::execute("www.baidu.com", "80", req2, std::chrono::seconds(3)); if (asio2::get_last_error()) std::cout << asio2::last_error_msg() << std::endl; else std::cout << rep2 << std::endl; // POST auto req4 = http::make_request("POST / HTTP/1.1\r\nHost: 192.168.0.1\r\n\r\n"); auto rep4 = asio2::http_client::execute("www.baidu.com", "80", req4); if (asio2::get_last_error()) std::cout << asio2::last_error_msg() << std::endl; else std::cout << rep4 << std::endl; // GET http::web_request req6(http::verb::get, "/", 11); req6.set(http::field::user_agent, "Chrome"); auto rep6 = asio2::http_client::execute("www.baidu.com", "80", req6, sock5_option); if (asio2::get_last_error()) std::cout << asio2::last_error_msg() << std::endl; else std::cout << rep6 << std::endl; // POST http::web_request req7; req7.method(http::verb::post); req7.target("/"); req7.set(http::field::user_agent, "Chrome"); req7.set(http::field::content_type, "text/html"); req7.body() = "Hello World."; req7.prepare_payload(); auto rep7 = asio2::http_client::execute("www.baidu.com", "80", req7); if (asio2::get_last_error()) std::cout << asio2::last_error_msg() << std::endl; else std::cout << rep7 << std::endl; // convert the response body to string std::stringstream ss1; ss1 << rep7.body(); std::cout << ss1.str() << std::endl; // convert the whole response to string std::stringstream ss2; ss2 << rep7; std::cout << ss2.str() << std::endl; asio2::http_client client; client.bind_recv([&](http::web_request& req, http::web_response& rep) { // print the whole response std::cout << rep << std::endl; // print the response body std::cout << rep.body() << std::endl; // convert the response body to string std::stringstream ss; ss << rep.body(); std::cout << ss.str() << std::endl; // Remove all fields req.clear(); req.set(http::field::user_agent, "Chrome"); req.set(http::field::content_type, "text/html"); req.method(http::verb::get); req.keep_alive(true); req.target("/get_user?name=abc"); req.body() = "Hello World."; req.prepare_payload(); client.async_send(std::move(req)); }).bind_connect([&]() { if (asio2::get_last_error()) printf("connect failure : %d %s\n", asio2::last_error_val(), asio2::last_error_msg().c_str()); else printf("connect success : %s %u\n", client.local_address().c_str(), client.local_port()); // connect success, send a request. if (!asio2::get_last_error()) { const char * msg = "GET / HTTP/1.1\r\n\r\n"; client.async_send(msg); } }); client.start(host, port/*, sock5_option*/); while (std::getchar() != '\n'); return 0; }