目录
[5.在 url 中传递参数的原理](#5.在 url 中传递参数的原理)
[5.2.浏览器本地预处理(输入 URL 后,发请求前)](#5.2.浏览器本地预处理(输入 URL 后,发请求前))
[5.3.建立 TCP 连接](#5.3.建立 TCP 连接)
[5.4.浏览器发送 HTTP 请求报文](#5.4.浏览器发送 HTTP 请求报文)
[5.6.服务端返回 HTTP 响应报文](#5.6.服务端返回 HTTP 响应报文)
[8.QtWebEngine 拼接 URL 携带 Token](#8.QtWebEngine 拼接 URL 携带 Token)
[9.asio2 内置 URL 工具(http 命名空间)](#9.asio2 内置 URL 工具(http 命名空间))
1.基于asio2实现的http示例代码
源码如下:
cpp
#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核数,启动对于核数的线程,如果控制启动的线程数,可以手动传入参数,如:
cpp
asio2::http_server server(1); //1个线程
http客户端(如浏览器)发送请求是并发的,服务端多线程处理,就会涉及到并发的去访问文件、数据库、网络等资源,设计的时候需要考虑到。
3.在绑定的路由请求中获取请求的远程的IP和端口
cpp
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>)作为第一个参数传入。你需要通过这个会话对象来获取远端地址和端口。
cpp
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.静态资源绑定
cpp
// 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 完全不参与 |
cpp
// 完整原始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=abc123
2.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的方法:
cpp
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.跨域处理
cpp
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
cpp
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,不支持裸中文直接请求:
cpp
#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。
完整的示例如下:
cpp
#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;
}