← 返回主页

C++ REST SDK (Casablanca) 使用指南

C++ REST SDK (代号 Casablanca) 是微软开发的一个跨平台 C++ 库,用于构建现代的、连接云服务的 C++ 应用程序。它提供了 HTTP 客户端/服务器、JSON 处理、WebSocket 支持、异步任务等功能,适合构建 RESTful 服务和客户端。

📦 安装

Ubuntu/Debian

# 安装依赖
sudo apt-get install libboost-all-dev libssl-dev

# 从源码编译
git clone https://github.com/microsoft/cpprestsdk.git
cd cpprestsdk
mkdir build && cd build
cmake ..
cmake --build .
sudo make install

macOS (使用 Homebrew)

brew install cpprestsdk

Windows (vcpkg)

vcpkg install cpprestsdk:x64-windows

🚀 基础使用

HTTP GET 请求

#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
#include <iostream>

using namespace web;
using namespace web::http;
using namespace web::http::client;

int main() {
    // 创建 HTTP 客户端
    http_client client(U("https://api.github.com"));

    // 发送 GET 请求
    client.request(methods::GET, U("/users/microsoft"))
    .then([](http_response response) {
        // 检查状态码
        if (response.status_code() == status_codes::OK) {
            // 读取响应体
            return response.extract_json();
        }
        return pplx::task_from_result(json::value());
    })
    .then([](json::value jsonValue) {
        // 解析 JSON
        if (!jsonValue.is_null()) {
            utility::string_t login = jsonValue.at(U("login")).as_string();
            std::wcout << L"Login: " << login << std::endl;
            
            utility::string_t html_url = jsonValue.at(U("html_url")).as_string();
            std::wcout << L"URL: " << html_url << std::endl;
        }
    })
    .wait(); // 等待异步操作完成

    return 0;
}

HTTP POST 请求

#include <cpprest/http_client.h>
#include <iostream>

using namespace web;
using namespace web::http;
using namespace web::http::client;

int main() {
    http_client client(U("https://httpbin.org/post"));

    // 创建 JSON 请求体
    json::value postData;
    postData[U("name")] = json::value::string(U("Alice"));
    postData[U("age")] = json::value::number(25);
    postData[U("active")] = json::value::boolean(true);

    // 发送 POST 请求
    client.request(methods::POST, U(""), postData.to_string())
    .then([](http_response response) {
        if (response.status_code() == status_codes::OK) {
            return response.extract_json();
        }
        return pplx::task_from_result(json::value());
    })
    .then([](json::value responseJson) {
        // 打印响应
        if (!responseJson.is_null()) {
            std::wcout << responseJson.serialize() << std::endl;
        }
    })
    .wait();

    return 0;
}

HTTP PUT 请求

#include <cpprest/http_client.h>
#include <iostream>

using namespace web;
using namespace web::http;
using namespace web::http::client;

int main() {
    http_client client(U("https://jsonplaceholder.typicode.com/posts/1"));

    // 创建更新数据
    json::value updateData;
    updateData[U("title")] = json::value::string(U("Updated Title"));
    updateData[U("body")] = json::value::string(U("Updated body content"));

    // 发送 PUT 请求
    client.request(methods::PUT, U(""), updateData.to_string())
    .then([](http_response response) {
        if (response.status_code() == status_codes::OK) {
            return response.extract_json();
        }
        return pplx::task_from_result(json::value());
    })
    .then([](json::value responseJson) {
        std::wcout << L"Updated: " << responseJson.serialize() << std::endl;
    })
    .wait();

    return 0;
}

HTTP DELETE 请求

#include <cpprest/http_client.h>
#include <iostream>

using namespace web;
using namespace web::http;
using namespace web::http::client;

int main() {
    http_client client(U("https://jsonplaceholder.typicode.com/posts/1"));

    // 发送 DELETE 请求
    client.request(methods::DEL)
    .then([](http_response response) {
        std::wcout << L"Status Code: " << response.status_code() << std::endl;
        return response.extract_string();
    })
    .then([](utility::string_t responseText) {
        std::wcout << L"Response: " << responseText << std::endl;
    })
    .wait();

    return 0;
}

🔧 JSON 处理

创建和解析 JSON

#include <cpprest/json.h>
#include <iostream>

using namespace web;
using namespace web::json;

int main() {
    // 创建 JSON 对象
    json::value user;
    user[U("id")] = json::value::number(1);
    user[U("name")] = json::value::string(U("Alice"));
    user[U("active")] = json::value::boolean(true);
    
    // 创建 JSON 数组
    json::value hobbies = json::value::array();
    hobbies[0] = json::value::string(U("reading"));
    hobbies[1] = json::value::string(U("coding"));
    hobbies[2] = json::value::string(U("gaming"));
    user[U("hobbies")] = hobbies;

    // 序列化为字符串
    utility::string_t jsonStr = user.serialize();
    std::wcout << L"JSON: " << jsonStr << std::endl;

    // 解析 JSON 字符串
    json::value parsed = json::value::parse(jsonStr);
    
    // 访问字段
    utility::string_t name = parsed.at(U("name")).as_string();
    int id = parsed.at(U("id")).as_integer();
    bool active = parsed.at(U("active")).as_bool();
    
    std::wcout << L"Name: " << name << std::endl;
    std::wcout << L"ID: " << id << std::endl;
    std::wcout << L"Active: " << (active ? L"Yes" : L"No") << std::endl;

    // 遍历数组
    if (parsed.has_field(U("hobbies")) && parsed.at(U("hobbies")).is_array()) {
        json::array hobbiesArray = parsed.at(U("hobbies")).as_array();
        std::wcout << L"Hobbies:" << std::endl;
        for (const auto& hobby : hobbiesArray) {
            std::wcout << L"  - " << hobby.as_string() << std::endl;
        }
    }

    return 0;
}

嵌套 JSON 处理

#include <cpprest/json.h>
#include <iostream>

using namespace web;
using namespace web::json;

int main() {
    // 创建嵌套 JSON
    json::value company;
    company[U("name")] = json::value::string(U("TechCorp"));
    
    // 嵌套地址对象
    json::value address;
    address[U("street")] = json::value::string(U("123 Tech Street"));
    address[U("city")] = json::value::string(U("San Francisco"));
    address[U("zip")] = json::value::string(U("94102"));
    company[U("address")] = address;
    
    // 嵌套员工数组
    json::value employees = json::value::array();
    
    json::value emp1;
    emp1[U("id")] = json::value::number(1);
    emp1[U("name")] = json::value::string(U("Alice"));
    employees[0] = emp1;
    
    json::value emp2;
    emp2[U("id")] = json::value::number(2);
    emp2[U("name")] = json::value::string(U("Bob"));
    employees[1] = emp2;
    
    company[U("employees")] = employees;

    std::wcout << company.serialize() << std::endl;

    // 访问嵌套字段
    utility::string_t city = company.at(U("address")).at(U("city")).as_string();
    std::wcout << L"City: " << city << std::endl;

    return 0;
}

🌐 HTTP 服务器

创建简单的 REST 服务器

#include <cpprest/http_listener.h>
#include <cpprest/json.h>
#include <iostream>

using namespace web;
using namespace web::http;
using namespace web::http::experimental::listener;

void handle_get(http_request request) {
    // 构造 JSON 响应
    json::value response;
    response[U("message")] = json::value::string(U("Hello, World!"));
    response[U("status")] = json::value::string(U("success"));

    // 发送响应
    request.reply(status_codes::OK, response);
}

void handle_post(http_request request) {
    // 读取请求体
    request.extract_json()
    .then([request](pplx::task<json::value> task) {
        try {
            json::value jsonData = task.get();
            
            // 处理数据
            utility::string_t name = jsonData.at(U("name")).as_string();
            
            // 构造响应
            json::value response;
            response[U("greeting")] = json::value::string(
                U("Hello, ") + name + U("!")
            );
            response[U("status")] = json::value::string(U("success"));
            
            request.reply(status_codes::OK, response);
        } catch (const std::exception& e) {
            json::value error;
            error[U("error")] = json::value::string(U("Invalid JSON"));
            request.reply(status_codes::BadRequest, error);
        }
    }).wait();
}

int main() {
    // 创建 HTTP 监听器
    http_listener listener(U("http://localhost:8080/api"));

    // 注册路由
    listener.support(methods::GET, handle_get);
    listener.support(methods::POST, handle_post);

    try {
        // 启动监听
        listener.open().wait();
        std::wcout << L"Server running at http://localhost:8080/api" << std::endl;
        std::wcout << L"Press Enter to exit..." << std::endl;
        std::cin.get();
        
        // 停止监听
        listener.close().wait();
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
}

🔌 WebSocket

WebSocket 客户端

#include <cpprest/ws_client.h>
#include <iostream>

using namespace web;
using namespace web::websockets;
using namespace web::websockets::client;

int main() {
    // 创建 WebSocket 客户端
    websocket_callback_client client;

    // 配置消息接收回调
    client.set_message_handler([](const websocket_incoming_message& msg) {
        utility::string_t message = msg.extract_string().get();
        std::wcout << L"Received: " << message << std::endl;
    });

    // 连接到服务器
    client.connect(U("ws://echo.websocket.org")).wait();
    std::wcout << L"Connected to WebSocket server" << std::endl;

    // 发送消息
    websocket_outgoing_message msg;
    msg.set_utf8_message("Hello from C++ REST SDK!");
    client.send(msg).wait();
    std::wcout << L"Message sent" << std::endl;

    // 等待一会儿接收响应
    std::this_thread::sleep_for(std::chrono::seconds(2));

    // 关闭连接
    client.close().wait();
    std::wcout << L"Connection closed" << std::endl;

    return 0;
}

🔍 高级功能

设置请求头

#include <cpprest/http_client.h>
#include <iostream>

using namespace web;
using namespace web::http;
using namespace web::http::client;

int main() {
    http_client client(U("https://httpbin.org/headers"));

    // 创建请求
    http_request request(methods::GET);
    
    // 设置自定义请求头
    request.headers().add(U("User-Agent"), U("C++ REST SDK Client"));
    request.headers().add(U("Accept"), U("application/json"));
    request.headers().add(U("X-Custom-Header"), U("CustomValue"));

    // 添加认证头
    utility::string_t auth = U("Bearer ") + U("your-token-here");
    request.headers().add(U("Authorization"), auth);

    // 发送请求
    client.request(request)
    .then([](http_response response) {
        return response.extract_json();
    })
    .then([](json::value jsonValue) {
        std::wcout << jsonValue.serialize() << std::endl;
    })
    .wait();

    return 0;
}

文件上传

#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
#include <iostream>
#include <fstream>

using namespace web;
using namespace web::http;
using namespace web::http::client;

int main() {
    http_client client(U("https://httpbin.org/post"));

    // 创建文件流
    concurrency::streams::fstream fileStream = 
        concurrency::streams::fstream::open_istream(
            U("example.txt"),
            std::ios::in
        ).get();

    // 创建多部分表单数据
    http_request request(methods::POST);
    
    // 设置请求体为文件内容
    request.set_body(fileStream);
    request.headers().set_content_type(U("text/plain"));

    // 发送请求
    client.request(request)
    .then([](http_response response) {
        std::wcout << L"Status: " << response.status_code() << std::endl;
        return response.extract_string();
    })
    .then([](utility::string_t responseText) {
        std::wcout << L"Response: " << responseText << std::endl;
    })
    .wait();

    fileStream.close().wait();
    return 0;
}

异步请求链

#include <cpprest/http_client.h>
#include <iostream>

using namespace web;
using namespace web::http;
using namespace web::http::client;

int main() {
    http_client client(U("https://jsonplaceholder.typicode.com"));

    // 链式异步请求
    client.request(methods::GET, U("/users/1"))
    .then([](http_response response) {
        return response.extract_json();
    })
    .then([&client](json::value userJson) {
        // 获取第一个用户的 ID
        utility::string_t userId = userJson.at(U("id")).as_string();
        
        // 使用第一个用户的 ID 获取该用户的帖子
        utility::string_t postsPath = U("/posts?userId=") + userId;
        return client.request(methods::GET, postsPath);
    })
    .then([](http_response response) {
        return response.extract_json();
    })
    .then([](json::value postsJson) {
        // 打印所有帖子的标题
        if (postsJson.is_array()) {
            for (const auto& post : postsJson.as_array()) {
                utility::string_t title = post.at(U("title")).as_string();
                std::wcout << L"Title: " << title << std::endl;
            }
        }
    })
    .wait();

    return 0;
}

💼 实际应用示例

REST API 客户端封装

#include <cpprest/http_client.h>
#include <cpprest/json.h>
#include <string>
#include <memory>

using namespace web;
using namespace web::http;
using namespace web::http::client;

class ApiClient {
private:
    http_client client_;
    utility::string_t base_url_;

public:
    ApiClient(const utility::string_t& baseUrl) 
        : client_(baseUrl), base_url_(baseUrl) {}

    // GET 请求
    pplx::task<json::value> get(const utility::string_t& path) {
        return client_.request(methods::GET, path)
        .then([](http_response response) {
            if (response.status_code() != status_codes::OK) {
                throw std::runtime_error("HTTP Error");
            }
            return response.extract_json();
        });
    }

    // POST 请求
    pplx::task<json::value> post(
        const utility::string_t& path,
        const json::value& data) {
        return client_.request(methods::POST, path, data)
        .then([](http_response response) {
            if (response.status_code() != status_codes::OK &&
                response.status_code() != status_codes::Created) {
                throw std::runtime_error("HTTP Error");
            }
            return response.extract_json();
        });
    }

    // PUT 请求
    pplx::task<json::value> put(
        const utility::string_t& path,
        const json::value& data) {
        return client_.request(methods::PUT, path, data)
        .then([](http_response response) {
            if (response.status_code() != status_codes::OK) {
                throw std::runtime_error("HTTP Error");
            }
            return response.extract_json();
        });
    }

    // DELETE 请求
    pplx::task<bool> del(const utility::string_t& path) {
        return client_.request(methods::DEL, path)
        .then([](http_response response) {
            return response.status_code() == status_codes::OK;
        });
    }
};

int main() {
    ApiClient api(U("https://jsonplaceholder.typicode.com"));

    // 获取用户
    api.get(U("/users/1"))
    .then([](json::value user) {
        std::wcout << L"User: " << user.serialize() << std::endl;
    }).wait();

    // 创建新帖子
    json::value newPost;
    newPost[U("title")] = json::value::string(U("My Post"));
    newPost[U("body")] = json::value::string(U("Post body"));
    newPost[U("userId")] = json::value::number(1);

    api.post(U("/posts"), newPost)
    .then([](json::value createdPost) {
        std::wcout << L"Created: " << createdPost.serialize() << std::endl;
    }).wait();

    return 0;
}

📋 常用类和方法速查

类别 类/方法 说明
HTTP 客户端 http_client HTTP 客户端类
request() 发送 HTTP 请求
http_response HTTP 响应类
extract_json() 提取 JSON 响应
JSON 处理 json::value JSON 值类
parse() 解析 JSON 字符串
serialize() 序列化为字符串
json::array() 创建 JSON 数组
HTTP 方法 methods::GET GET 请求
methods::POST POST 请求
methods::PUT/DEL PUT/DELETE 请求
WebSocket websocket_client WebSocket 客户端
websocket_listener WebSocket 服务端
💡 提示: C++ REST SDK 使用 PPL (Parallel Patterns Library) 处理异步操作,.then() 方法用于链式处理异步结果。记得在主程序最后调用 .wait() 来等待异步操作完成。
⚠️ 注意:

🔗 参考资料