c++如何使用rest sdk调用接口_c++ cpprestsdk异步请求与json解析【实战】

cpprestsdk发起POST需设content_type并用extract_json()解析响应,异步请求须用then链式处理,URI拼接推荐uri_builder。

cpprestsdk 发起 POST 请求并解析 JSON 响应

cpprestsdk(即 Casablanca)本身不内置 JSON Schema 验证,但提供 json::value 类型支持原生解析和构造。异步请求必须搭配 then() 链式处理,不能直接用 get() 同步阻塞(尤其在 UI 线程或高并发服务中易引发死锁)。

  • http_client 构造时 URL 末尾不加斜杠不影响请求,但路径拼接建议统一由 uri_builder 处理,避免手动字符串拼接出错
  • POST body 必须显式设置 content_type,否则服务端可能拒收:L"application/json" 是最常用值,注意宽字符前缀 L
  • 响应体读取必须调用 response.extract_json(),不能直接对 response.body()json::value::parse() —— 后者会丢弃编码信息且不处理流式响应
auto client = http_client(U("https://api.example.com"));
auto req = http_request(methods::POST);
req.set_request_uri(U("/v1/data"));
req.headers().add(U("Authorization"), U("Bearer abc123"));
req.set_body(json::value::object({
    { U("query"), json::value::string(U("user")) },
    { U("limit"), json::value::number(10) }
}).serialize(), U("application/json"));

client.request(req).then([](http_response response) -> pplx::task {
    if (response.status_code() != status_codes::OK) {
        throw std::runtime_error("HTTP error: " + std::to_string(response.status_code()));
    }
    return response.extract_json(); // ← 关键:必须用 extract_json()
}).then([](json::value json_obj) {
    auto items = json_obj.at(U("results")).as_array();
    for (const auto& item : items) {
        wcout << item.at(U("id")).as_string() << endl;
    }
}).wait(); // 仅调试用;生产环境应延续 then 链或用 .get() 在独立线程

异步链中捕获网络异常与 HTTP 错误

cpprestsdk 的异常不是标准 std::exception 子类,而是 web::http::http_exception 或底层 std::system_error。直接 try/catch 外层任务会漏掉内部异步阶段抛出的异常 —— 必须在每个 then() 回调里检查 response.status_code(),或统一用 .then([](pplx::task<:value> t) { try { t.get(); } catch(...) {...} }) 包裹。

  • http_exception 通常来自 DNS 失败、连接超时、SSL 握手失败等,t.get() 会 rethrow 它
  • HTTP 4xx/5xx 响应不会自动抛异常,需手动判断 status_code() 并决定是否 throw
  • 超时需在 http_client_config 中设置:config.set_timeout(std::chrono::seconds(15));,否则默认无超时

json::value 解析常见陷阱

json::value 是引用语义,频繁调用 at() 可能抛 json_exception(键不存在),且不支持类似 Python 的 .get(key, default) 模式。嵌套深时容易写成 obj.at(U("a")).at(U("b")).at(U("c")),一旦中间某层缺失就崩溃。

  • 安全访问推荐先用 has_field() 判断,再 at();或封装工具函数如 safe_get(obj, {U("a"), U("b"), U("c")})
  • as_string() 返回 utility::string_t(即 std::wstring),若服务端返回 UTF-8 字符串但未声明 Content-Type: application/json; charset=utf-8,可能乱码 —— 此时需手动用 utf8_to_utf16() 转换
  • 数值类型区分 as_number()(浮点)和 as_integer()(整型),但 JSON 标准无整数/浮点之分,服务端传 42.0 会导致 as_integer() 抛异常

Windows 下链接 cpprestsdk 的关键配置

Visual Studio 项目必须同时满足三项,缺一不可,否则出现 LNK2019 找不到 http_client::request 等符号:

  • 附加依赖项加入:cpprest142_2_10.lib(版本号随 SDK 更新变化,查 %VCPKG_ROOT%\installed\x64-windows\lib 确认)
  • C/C++ → 语言 → 符合模式 设为“否”,否则 C++17 的某些特性(如 structured binding)会与 SDK 冲突
  • 预处理器定义添加:_NO_ASYNCRTIMP(禁用动态链接 AsyncRT,避免 DLL 版本不匹配)

Linux/macOS 用户用 vcpkg 安装后,链接时需确保 -lcpprest -lboost_system -lssl -lcrypto -lz 顺序正确,libssl 必须在 libcpprest 之后。