最稳妥方式是手动解析:先找'?'定位query,再按'&'分割并跳过空段,用'='拆键值对,最后URL解码key和value;需处理'+'作为空格、%XX十六进制解码及非法编码保留。

用 std::string 手动解析 query 字符串最稳妥
标准 C++ 没有内置 URL 解析库,std::url 还在 TS 阶段且未进正式标准,别指望 #include <url></url>。实际项目里,多数人直接切分 ? 后的字符串,再按 & 和 = 拆键值对——简单、可控、不依赖第三方。
常见错误是没处理 URL 编码(比如空格变 %20、中文变 %E4%B8%AD),直接 find("=") 就取值,结果拿到一堆乱码或截断。还有人用 std::stringstream 按 & 分割,但没跳过空段(比如 a=1&&b=2 中间那个空字符串)。
- 先用
find('?')定位 query 起始位置,没找到就整个字符串当 path 处理 - 对 query 子串按
&切分时,跳过长度为 0 的片段 - 每个键值对用
find('=')分割:没等号的当 key(值设为空字符串),等号在开头的 key 为空(如=1)要保留原语义 - 必须调用 URL 解码函数处理 key 和 value;可手写简单版(只处理
%XX十六进制转字节),别用系统curl_easy_unescape这类 C 接口,容易内存泄漏
用 libcurl 的 curl_easy_escape / curl_free 反而更麻烦
有人想“既然 curl 能发 HTTP,那它肯定能解析 URL”,于是翻文档找 curl_url 相关 API。问题在于:curl_url 是 libcurl 7.62.0+ 新增的,旧版本不可用;而且它设计目标是构造/修改 URL,不是解析查询参数——curl_url_get(u, CURLUPART_QUERY, &out, 0) 只返回整个 query 字符串,你还是得自己拆。
更关键的是,curl_easy_escape 是编码函数,不是解码;它的反向操作 curl_easy_unescape 返回的是 char *,必须配对调用 curl_free,否则内存泄漏。C 风格接口混进 C++ 代码里,RAII 管理很容易漏掉。
立即学习“C++免费学习笔记(深入)”;
- 除非你 already 重度依赖 libcurl 且版本 ≥7.62.0,否则别为了 parse query 引入它
-
curl_url_get(..., CURLUPART_QUERY, ...)返回的仍是 raw query string,不解码也不分割 - 若真要用,务必检查返回值是否为
CURLE_OK,且out非空指针;curl_free(out)必须执行,不能靠智能指针自动管理
用 std::regex 匹配 key=value 容易漏边角 case
正则看起来很干净:std::regex re("([^&=]+)=([^&]*)"),循环 regex_iterator 提取。但实际跑起来会发现:带嵌套 = 的 value(如 json=%7B%22a%22%3A1%7D)被提前截断;开头或结尾的 & 导致首尾匹配失败;URL 编码后的 =(即 %3D)被当成分隔符误切。
根本问题是:正则在解码前工作,而 URL 编码破坏了语法结构。你不能指望一个没上下文的模式去区分 “真正的分隔符” 和 “编码后的字符”。
- 正则只适合 post-decode 的 clean 字符串,别让它碰 raw query
- 如果坚持用 regex,必须先完整解码整个 query,再喂给正则——但此时手动切分已足够快,正则反而增加开销
-
std::regex在 MSVC 上性能较差,某些 pattern 还有栈溢出风险(尤其长 query)
注意 application/x-www-form-urlencoded 的特殊规则
HTTP 查询参数默认遵循这个编码规范,但它和通用 URL 编码略有不同:空格应编码为 +(而非 %20),+ 本身要编码为 %2B。很多手写解码函数只处理 %XX,忘了把 + 替换成空格,导致表单提交的参数解析错乱。
另外,重复 key(如 a=1&a=2)是合法的,但 C++ 标准容器如 std::map 会覆盖,std::unordered_map 同样不支持多值。真遇到这种需求,得用 std::vector<:pair std::string>></:pair> 或 std::multimap。
- 解码时优先替换
+→' ',再处理所有%[0-9A-Fa-f]{2} - 对
%后非十六进制字符(如%G1)应保留原样,不强行解码 - 如果业务明确需要多值支持,别图省事用
map,multimap::equal_range是现成方案
最麻烦的永远不是怎么拆字符串,而是边界情况:空 query、只有 key 没 value、value 里有未闭合的 %、各种编码混用。写三行正则解决不了的问题,往往得靠五条 if 判断兜底。









