简介:cpr-1.3.0 预编译库面向使用 C++ 发起 HTTP 请求的开发者,适合在 VS 项目中快速接入、又不想自行编译 cpr 与 libcurl 的初、中级人员。压缩包共 27 个文件,含 21 个头文件、4 个 lib 静态库和 2 个 dll 动态库,Debug/Release 均提供 cpr.lib、libcurl.dll 等,整体约 738KB,便于随工程归档引用。资源由 weststarqp 于 2019 年 2 月基于 VS2015 编译,已有 691 人学习。解压后可按配置将头文件、库文件与动态库加入工程,减少搭建依赖环境的时间,并借助头文件了解 session、response、auth、cookies 等接口,为请求封装和调试提供基础。
1. 从一次"库在,头文件不在"的编译失败说起
上周接手一个内部工具的构建,CMakeLists 里一行find_package(cpr REQUIRED),我以为是十分钟的事,结果make直接甩出一堆fatal error: cpr/generated/cpr_generated_includes.h: No such file or directory。库文件明明装了,头文件目录也加进-I了,偏偏缺一个名字很长的中间头文件。这就是 cpr 1.3.0 最经典的一关。cpr 全称 C++ Requests,是把 libcurl 那套 C 接口包成cpr::Get/cpr::Response风格的 C++11 库,写 HTTP 客户端时不用再和curl_easy_setopt的变参列表较劲。它常见于数据采集、内部服务探活、CI 里的小工具这类场景。装不顺的后果很直接:编译期缺头,链接期缺符号,运行期 SSL 握手失败,一路踩下来比手写 libcurl 还费时间。这篇记录适合正在找 cpr-1.3.0 怎么安装、怎么配置、环境怎么搭的人。
2. 环境盘点:cpr 1.3.0 编起来到底要哪几样东西
动手之前先把依赖列清楚,比编到一半再回头补要省事得多。cpr 1.3.0 本身不复杂,它就是一层薄封装,真正的重活在 libcurl 和 OpenSSL 上。麻烦的地方在于它的 CMake 脚本默认行为偏"自给自足",会尝试自己去弄 curl 源码,这在有外网的开发机上无感,在隔离环境里就是灾难。所以这一章的重点不是罗列依赖,而是把每个依赖的"来源"定下来:编译器从系统来,curl 从系统来,SSL 从系统来,三样都锁死,构建过程才是可复现的。
2.1 编译器与 C++ 标准:C++11 是底线,不是可选项
cpr 1.3.0 的公开头文件里用了std::function、std::unordered_map、右值引用和大量 lambda,编译选项里必须打开 C++11。GCC 建议 7 以上,Clang 建议 6 以上,MSVC 走 2017 以后的版本比较稳。我一般不去赌默认标准,而是在工程顶层直接写死,避免某个下游工程把-std覆盖掉之后,报出一堆看不懂的模板推导错误。
# 顶层 CMakeLists.txt,在 project() 之后立刻设置 set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 找不到 C++11 编译器就直接失败,而不是悄悄降级 set(CMAKE_CXX_EXTENSIONS OFF) # 关掉 gnu++11,保持可移植这三行的逻辑是:第一行声明目标标准,第二行把"必须有"变成硬约束,第三行避免编译期混入 GNU 扩展导致换编译器就编不过。很多"在我机器上能编"的事故,源头就是CMAKE_CXX_EXTENSIONS默认开着,代码里不小心用了typeof之类的东西,换到 Clang 上直接崩。如果你的工程已经是 C++14 或 C++17,不用降级,cpr 1.3.0 在更高标准下也能编,只是别把-std=c++98这种老配置带进来。
2.2 libcurl 用系统的还是自带的:一个决定影响后面所有链接错误
cpr 的 CMake 里有一个开关叫CPR_FORCE_USE_SYSTEM_CURL,默认是关闭的。关闭状态下,构建脚本会尝试把 curl 源码弄到本地再一起编。这个设计对想"零依赖"的人友好,但在实际部署里问题不少:构建过程会依赖外部源码获取,网络受限时直接卡住;就算拿到了源码,编出来的 curl 和系统里其他程序用的 curl 也是两份,后面做动态链接时符号容易打架。
我的做法是一律强制用系统 curl,前提是先确认开发包装好了:
# Debian / Ubuntu 系,装 curl 的开发头文件和静态库 sudo apt-get install -y libcurl4-openssl-dev # RHEL / CentOS 系 sudo yum install -y libcurl-devel # 确认系统里的 curl 版本,低于 7.50 建议先升级 curl-config --version curl-config --libs # 看链接参数里是否带 -lssl -lcryptolibcurl4-openssl-dev这个名字不是随便挑的,它决定了 curl 背后用的是 OpenSSL 而不是别的 TLS 实现。cpr 的 SSL 相关代码路径和 curl 的 TLS 后端是绑定的,混用会出现"编译通过但运行期证书校验行为异常"这种很难查的问题。curl-config --libs的输出要重点看,如果里面没有-lssl -lcrypto,说明装的是不带 SSL 的版本,后面CPR_ENABLE_SSL=ON会直接失败。装完开发包后再跑一次curl-config --version,把版本号记下来,后面排查时有用。
2.3 OpenSSL 与 zlib:SSL 开关背后的两个真实依赖
cpr 1.3.0 的CPR_ENABLE_SSL默认打开,打开之后就会去找 OpenSSL 的头文件和库。1.1.1 系列是目前兼容性最好的选择,如果系统里是 3.x,多数情况下也能编,但要留意 cpr 这层封装里对旧宏的引用,个别发行版会报OPENSSL_VERSION_NUMBER相关的弃用警告,警告本身不影响产物,但会淹没真正的错误信息。
zlib 的情况稍微特殊一点,cpr 本身不直接用 zlib,但 curl 在开启内容压缩支持时会依赖它。如果你的请求需要带Accept-Encoding: gzip,那 curl 编的时候就必须带 zlib,否则服务端返回压缩体时你拿到的是乱码。检查办法很直接:
# 看 curl 的编译特性里有没有 zlib 和 SSL curl -V # 输出里的 Features 一行,应包含 libz、SSL、HTTPS-proxy 等关键字这一步属于"装之前花十秒,装之后省两小时"的检查。很多环境里 curl 是精简版编译的,特性列表里没有 libz,等到业务代码里手动解压失败才发现,回头重装 curl 还得连带重编 cpr,代价不小。
2.4 一套我常用的版本组合
下面这张表是我这几年在不同机器上落地过的组合,不是官方要求,只是"这个范围内我没翻过车"的经验区间。跨大版本时差异会放大,比如把 curl 从 7.x 换到 8.x,链接参数和部分宏定义都有变化,需要重新验证一遍。
| 组件 | 推荐区间 | 说明 |
|---|---|---|
| CMake | 3.10 及以上 | 低版本对target_include_directories的 install 导出支持不全 |
| GCC | 7 及以上 | 低于 7 时 C++11 的std::string_view替代实现容易出问题 |
| Clang | 6 及以上 | 与 libstdc++ 搭配时注意版本匹配 |
| libcurl | 7.58 及以上 | 7.58 前后 SSL 相关宏有调整,1.3.0 在旧版上偶发编译错误 |
| OpenSSL | 1.1.1 系列 | 兼容性最好,3.x 可用但会有弃用警告 |
| zlib | 1.2.8 及以上 | 只影响压缩传输,不影响基础请求 |
这张表的意义在于缩小排查范围。当你遇到一个诡异的编译错误时,先对照表格确认自己不在边缘组合上,再去翻代码,效率会高很多。
3. 编译安装:把 cpr 1.3.0 装进一个干净前缀
到这一步依赖都齐了,可以开始编。我强烈建议装到独立前缀而不是/usr/local,原因很现实:cpr 1.3.0 是几年前的版本,你手上可能还有别的工程依赖更高版本的 cpr,全都塞进/usr/local之后,find_package找到哪个全看运气。独立前缀加上CMAKE_PREFIX_PATH,能把这套依赖隔离得干干净净,卸载的时候一个rm -rf就完事,不留残渣。
3.1 源码落地与 out-of-source 构建目录
先建两个目录,一个放源码,一个放构建产物,严格分开。in-source 构建在 cpr 这种带代码生成的工程里尤其危险,中间文件会污染源码树,下次换配置时 CMakeCache 里全是脏数据。
# 目录规划:源码和产物分开,安装前缀独立 mkdir -p ~/work/cpr-1.3.0-src mkdir -p ~/work/build-cpr mkdir -p /opt/cpr-1.3.0 # 假设源码包已经解压到 ~/work/cpr-1.3.0-src cd ~/work/cpr-1.3.0-src ls CMakeLists.txt include/ # 确认目录结构对得上再往下走ls这一步别省。有些压缩包解开后多套一层目录,直接cmake -S .会报"找不到 CMakeLists.txt",新手容易在这里怀疑人生。确认CMakeLists.txt和include/在同一层,就是正确的源码根目录。安装前缀/opt/cpr-1.3.0里的版本号也别省,将来并存多个版本时,这个命名能救你一次。
3.2 CMake 关键选项逐个拆
配置阶段是整个安装过程里最值得花时间的地方。下面这条命令是我在大多数环境里用的版本,参数看着多,但每一项都对应一个具体的失败场景。
cmake -S ~/work/cpr-1.3.0-src \ -B ~/work/build-cpr \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/opt/cpr-1.3.0 \ -DCPR_BUILD_TESTS=OFF \ -DCPR_BUILD_SERVER=OFF \ -DCPR_ENABLE_SSL=ON \ -DCPR_FORCE_USE_SYSTEM_CURL=ON \ -DBUILD_SHARED_LIBS=ON \ -DCMAKE_POSITION_INDEPENDENT_CODE=ON逐项说明:
-S和-B是现代 CMake 的写法,分别指源码目录和构建目录,等价于进目录再跑cmake ..,但更不容易出错。CMAKE_BUILD_TYPE=Release打开优化并去掉调试符号。cpr 1.3.0 在 Debug 下编出来的库体积会大不少,作为依赖库没必要。CMAKE_INSTALL_PREFIX决定make install往哪写,这里就是前面建好的独立前缀。CPR_BUILD_TESTS=OFF很关键。打开后它会去找测试框架,在你没有预装的环境里会直接失败,而且测试代码本身对产物没有任何贡献。CPR_BUILD_SERVER=OFF关掉配套的测试服务端,同理。CPR_ENABLE_SSL=ON显式打开,别依赖默认值,尤其在别人写好的构建脚本里。CPR_FORCE_USE_SYSTEM_CURL=ON是前面 2.2 节说过的那个决定,必须显式指定。BUILD_SHARED_LIBS=ON出动态库。如果你的部署环境不方便带.so,改成OFF出静态库,这个取舍在第 4 章细说。CMAKE_POSITION_INDEPENDENT_CODE=ON保证生成的库能被链接进动态库,即使当前选的是静态库也建议开着。
配置跑完后,重点看输出的末尾几行,会打印出检测到的 curl 版本、SSL 后端、是否启用 zlib。这三行信息比任何文档都真实,因为它是从当前这台机器上探测出来的。
3.3 编译、安装,以及 generated 头文件这一关
cmake --build ~/work/build-cpr -j$(nproc) cmake --install ~/work/build-cpr-j后面跟并行度,用nproc拿到核数就行。cpr 本身编译很快,瓶颈通常在它要不要额外编 curl;一旦看到编译过程里出现了大量 curl 的源文件,说明 3.2 节那个开关没生效,回去检查参数拼写。
安装完之后必须做一次落地检查,这是整个流程里最容易被跳过、也最容易出问题的一步:
# 检查关键头文件和库是否真的落到了前缀目录 find /opt/cpr-1.3.0 -name "*.h" | head -20 find /opt/cpr-1.3.0 -name "libcpr*" ls /opt/cpr-1.3.0/lib/cmake/cpr/ 2>/dev/null || echo "缺 CMake 配置文件"三条命令分别查头文件、库文件、CMake 包配置。重点看头文件列表里有没有一个路径里带generated字样的文件——cpr 1.3.0 在构建时会生成一份与 curl 头文件版本相关的中间头文件,而老版本的安装规则在某些平台上不会把它一起装进去,于是出现第 1 章开头那个报错。如果确实缺了,从构建目录里找出来手动补进去:
# 在构建目录里定位生成的中间头文件 find ~/work/build-cpr -name "cpr_generated_includes.h" # 找到后按原相对路径补到安装前缀 mkdir -p /opt/cpr-1.3.0/include/cpr/generated cp ~/work/build-cpr/include/cpr/generated/cpr_generated_includes.h \ /opt/cpr-1.3.0/include/cpr/generated/补完之后再find一次确认。这一步属于典型的"官方安装规则没覆盖到"的坑,不补的话下游工程#include <cpr/cpr.h>必然失败,而且报错指向的是一个你没写过的文件名,第一眼很难联想到是安装不完整。CMake 里还有个CPR_GENERATED_SOURCES_DIRECTORY变量,可以用来指定生成物的输出位置,不同小版本行为不完全一致,我最后都会用上面这条手动校验兜底,不赌它的默认行为。
另外,如果目标是"直接拿现成的库文件用",那么落地检查同样适用:头文件树里必须有cpr/cpr.h、cpr/generated/下那个生成文件、lib/下的库,以及lib/cmake/cpr/下的配置文件,四样少一样都不算完整。少 CMake 配置文件的后果是find_package直接失败,很多人在这一步误以为是版本不匹配,其实只是安装不完整。
3.4 find_package 接入与 pkg-config 备选
安装到位之后,在下游工程里就该能直接找到了。标准写法:
# 下游工程的 CMakeLists.txt find_package(cpr REQUIRED) add_executable(probe main.cpp) target_link_libraries(probe PRIVATE cpr::cpr)find_package会去CMAKE_PREFIX_PATH里找cprConfig.cmake,所以如果装在/opt下,配置时要带上路径:
cmake -S . -B build -DCMAKE_PREFIX_PATH=/opt/cpr-1.3.0如果find_package报找不到,先别怀疑版本,按顺序查三件事:配置文件是否在lib/cmake/cpr/下、CMAKE_PREFIX_PATH是否传进去了、前置的 curl 是否也能被找到。第三条经常被忽略——cpr 的配置文件里会find_dependency(CURL),如果你把 cpr 装到了前缀里,但 curl 是系统包,通常没问题;反过来把 curl 也装在独立前缀里却忘了把那个前缀加进搜索路径,就会在find_package(cpr)这一行报出莫名其妙的依赖错误。
target_link_libraries里的cpr::cpr是导出目标名。个别打包方式下目标名会不一样,链接时报 "Target not found" 的话,打开cprConfig.cmake看一眼里面add_library(... IMPORTED)那行写的是什么名字,照着改即可,别去改系统文件。
对于不用 CMake 的老工程,还有一条退路是直接手写链接参数:
# 用 curl-config 拿 curl 的链接参数,再拼上 cpr 的库 g++ main.cpp -I/opt/cpr-1.3.0/include \ -L/opt/cpr-1.3.0/lib -lcpr \ $(curl-config --libs) -lssl -lcrypto -lz -o probe这条命令的每段都有用:-I指向 cpr 头文件,-L -lcpr指向库,curl-config --libs把 curl 需要的参数一次性展开,最后三个是 SSL 和压缩的显式依赖。顺序很重要,库要放在源文件后面,否则 GCC 会因为符号未解析而报错。
4. 工程接入:把 cpr 1.3.0 写进业务代码
库装好了只是开始,真正决定这套环境好不好用的是接入方式。cpr 1.3.0 的 API 设计很接近脚本语言的 HTTP 客户端,几行就能发请求,但也正因为太顺手,容易写出没有超时、没有错误分支、连接不复用的代码,上线之后在弱网环境里表现一塌糊涂。这一章从最小可运行例子往外扩,把参数取舍讲清楚。
4.1 最小可编译的 CMakeLists 与一次 GET
先跑通再说别的。下面这段是能编能跑的最小骨架:
#include <cpr/cpr.h> #include <iostream> int main() { // 用本地地址验证,避免引入外部依赖 cpr::Response r = cpr::Get( cpr::Url{"http://127.0.0.1:8080/health"}, cpr::Timeout{3000} // 整体超时,单位毫秒 ); // error.code 是传输层状态,status_code 是 HTTP 层状态,两者互不替代 if (r.error.code != cpr::ErrorCode::OK) { std::cerr << "transport: " << r.error.message << "\n"; return 2; } std::cout << "http=" << r.status_code << " body=" << r.text << "\n"; return 0; }关键在最后那个判断。cpr 把两类失败分得很清楚:r.error记录的是连接超时、DNS 失败、SSL 握手失败这类传输层问题,r.status_code记录的是服务端返回的 HTTP 状态码。只判断status_code是新手最常见的疏漏——连接都失败了,status_code是 0,业务逻辑会把它当成"服务端返回 0"处理,后面全乱。判断顺序永远是先看error.code,再看status_code。
配套的 CMakeLists 就是 3.4 节那几行,加上源文件即可。注意别在target_link_libraries里再手动补-lcurl,cpr::cpr已经把传递依赖带上了,重复链接在某些平台上会导致符号重复定义。
4.2 超时、重试与 SSL 校验的参数取舍
生产代码和 Demo 的差距基本都在这三个参数上。cpr 1.3.0 的超时是整体超时,不是连接超时和读取超时的分别设置,所以给值的时候要按业务最坏情况考虑。
#include <cpr/cpr.h> #include <chrono> #include <thread> #include <iostream> // 带退避的简单重试:只对传输层失败重试,HTTP 4xx 不重试 cpr::Response GetWithRetry(const std::string& url, int max_attempts = 3) { cpr::Response r; for (int i = 0; i < max_attempts; ++i) { cpr::Session s; s.SetUrl(cpr::Url{url}); s.SetTimeout(cpr::Timeout{2000}); // 单次请求 2 秒 s.SetConnectTimeout(cpr::ConnectTimeout{800}); // 建连单独限时 s.SetHeader(cpr::Header{{"User-Agent", "cpr-1.3.0-probe"}}); r = s.Get(); if (r.error.code == cpr::ErrorCode::OK) { return r; // 传输成功就返回,HTTP 层交给调用方判断 } std::this_thread::sleep_for(std::chrono::milliseconds(200 * (i + 1))); } return r; }这段的取舍点有三个。第一,Timeout和ConnectTimeout分开设,建连超时给得短一些,能快速判断目标是否可达,整体超时留出读取响应的时间。第二,重试只针对传输层错误,HTTP 500 这种服务端明确返回的结果不重试,重试反而可能放大故障。第三,退避用线性递增,简单够用,不需要引入额外依赖。
关于 SSL 校验,cpr 提供了cpr::VerifySsl{false}来跳过证书校验。这个开关在调试自签证书的内网服务时确实方便,但绝对不要出现在生产代码里。如果内网服务用的是自签证书,正确做法是把 CA 证书装进系统信任库,或者用cpr::SslOptions指定 CA 路径,而不是关校验。这条属于血泪经验,跳过校验的代码一旦进了主干,后面很难再摘出来。
4.3 静态链接与动态链接:部署时的取舍
装的时候BUILD_SHARED_LIBS选哪个,直接决定部署形态。
动态库的好处是多个程序共用一份libcpr.so,升级时替换文件即可,缺点是部署时必须带上.so,还得处理RPATH或者设LD_LIBRARY_PATH。cpr 依赖 curl,curl 又依赖 SSL 和 zlib,动态链接下这条依赖链上任何一环版本不匹配,运行期就是一个symbol lookup error。
静态库的好处是产物自包含,拷贝一个可执行文件就能跑,特别适合分发小工具或者塞进容器镜像。代价是体积变大,而且必须确保 curl 的静态库也在系统里——很多发行版的libcurl4-openssl-dev只带动态库,静态库在单独的包里,装漏了会在链接阶段报找不到libcurl.a。
我的习惯是:内部服务用动态库,方便统一升级;对外分发的小工具用静态库,减少环境依赖。如果选静态,安装 cpr 时把BUILD_SHARED_LIBS设为OFF,下游链接时确保-lcurl -lssl -lcrypto -lz都能找到静态版本。
4.4 复用 Session 而不是每次新建
cpr 的cpr::Get这种自由函数写法内部会新建一个 Session,用完销毁,连接自然也不复用。在请求量大的场景里,这会明显拖慢吞吐。改成显式持有 Session:
// 长生命周期的 Session,复用连接和 TLS 会话 cpr::Session session; session.SetUrl(cpr::Url{"http://127.0.0.1:8080/api/items"}); session.SetTimeout(cpr::Timeout{2000}); session.SetHeader(cpr::Header{{"Accept", "application/json"}}); // 同一个 Session 可以改参数后重复调用 session.SetParameters(cpr::Parameters{{"page", "1"}, {"size", "50"}}); cpr::Response first = session.Get(); session.SetParameters(cpr::Parameters{{"page", "2"}, {"size", "50"}}); cpr::Response second = session.Get();要注意 Session 不是线程安全的,一个实例只能在一个线程里用。多线程场景下每个线程各自持有 Session,别图省事搞个全局共享的,那种问题往往在高并发压测时才暴露,排查成本很高。
5. 常见排查:cpr 1.3.0 编译链接的五个翻车现场
这一章按"现象 → 原因 → 解决"记录五条实际遇到过的故障。它们的共同点是报错信息都不太直观,第一眼容易往错误的方向猜。
5.1 编译期三类报错
第一条,报fatal error: cpr/generated/cpr_generated_includes.h: No such file or directory。现象是库装了、头文件路径也加了,就是缺这一个文件。原因是 1.3.0 的安装规则没有把这个构建时生成的头文件一起装进去,具体表现随平台和 CMake 版本略有差异。解决就是 3.3 节那套:从构建目录find出来,按相对路径手动补到$PREFIX/include/cpr/generated/下,补完记得再find一次确认。
第二条,报大量undefined reference to curl_easy_...。现象是编译通过,链接阶段成片报错。原因是链接顺序不对,或者cpr::cpr的传递依赖没生效。解决是先确认用的是target_link_libraries(xxx PRIVATE cpr::cpr)而不是手写-lcpr;手写的话,库必须放在目标文件之后,并且补上$(curl-config --libs)。如果还是不行,检查是不是同时链接了系统里另一份 curl。
第三条,配置阶段卡住或者报下载失败。现象是cmake跑到一半长时间没动静,日志里出现获取外部源码的动作。原因就是CPR_FORCE_USE_SYSTEM_CURL没开,脚本在尝试自己弄 curl。解决是回到 3.2 节,把这个参数显式设为ON,然后删掉构建目录重新配置——注意是删掉整个构建目录,只改参数重跑,缓存的变量未必能覆盖干净。
5.2 链接与运行期两类报错
第四条,运行期报 SSL 相关错误,r.error.message里出现证书验证失败的字样。现象是请求某个 HTTPS 地址一直失败,换 HTTP 就正常。原因是 curl 编译时用的 TLS 后端和系统信任库路径对不上,或者时间不对导致证书被判定为未生效。解决是先跑curl -V确认 Features 里有 SSL,再用curl -v https://目标地址对照排查——如果命令行 curl 也失败,问题在系统层,跟 cpr 无关;如果命令行成功而 cpr 失败,检查链接的是不是另一份 curl。
第五条,程序启动就报找不到libcpr.so。现象是编译链接都通过了,执行时报共享库加载失败。原因是库装在非标准前缀,运行时加载器找不到。解决有三个层次:临时用LD_LIBRARY_PATH=/opt/cpr-1.3.0/lib ./probe验证,确认是路径问题;长期方案是在 CMake 里设置INSTALL_RPATH,或者把前缀写进/etc/ld.so.conf.d/后跑一次ldconfig。千万别把LD_LIBRARY_PATH写进全局 shell 配置文件,那会影响同一台机器上所有程序,后患无穷。
6. 验证跑通:三组对照把"能跑"和"跑对"分开
装完最忌讳的是"编译通过就完事"。我见过太多次编译没问题、一上真实网络就出状况的情况。下面这套验证分三层,一层比一层接近真实使用。
第一层,静态检查。确认四样东西齐全:
| 检查项 | 路径 | 缺失后果 |
|---|---|---|
| 主头文件 | /opt/cpr-1.3.0/include/cpr/cpr.h | 编译直接失败 |
| 生成头文件 | /opt/cpr-1.3.0/include/cpr/generated/cpr_generated_includes.h | 编译报找不到文件 |
| 库文件 | /opt/cpr-1.3.0/lib/libcpr.so或.a | 链接失败 |
| CMake 配置 | /opt/cpr-1.3.0/lib/cmake/cpr/cprConfig.cmake | find_package失败 |
第二层,本地回环验证。用一个本地起的小服务返回固定 JSON,跑第 4 章那个最小例子,确认status_code是 200、r.text内容正确、r.error.code是OK。这一步排除网络因素,验证的是"库链接正确、请求能发出去"。同时故意请求一个不存在的端口,确认r.error.code不是OK且程序走的是错误分支——错误分支没被验证过,等于没写。
第三层,真实环境验证。挑一个内网的 HTTPS 接口,用 Session 复用方式连发十次,观察两件事:十次全部成功,说明连接复用和 TLS 会话没出问题;r.elapsed从第二次开始明显下降,说明连接确实被复用了。如果十次耗时一样,说明每次都在重新建连,回去检查是不是不小心每次都新建了 Session。
最后给个习惯。从那以后我每次装完 cpr,都会把这三层验证做成一个verify.sh留在构建目录里,包含路径检查、本地回环请求、十次连发计时三段。原因很简单:这套依赖横跨编译器、curl、SSL 三层,任何一层动过,表现都可能变化,而人脑记不住上次验证时的细节。脚本跑一遍,输出的三行结果就是这份环境还能不能用的黑匣子记录,比回忆靠谱得多。装环境这事没有一劳永逸,只有每次都走一遍的后悔药。希望帮到你。
本文还有配套的精品资源,点击获取