如何在C++中不依赖推荐GraphQL库,用WebSocket实现GraphQL订阅?
在C++中实现GraphQL订阅(无需指定GraphQL库)
curlpp是HTTP客户端,仅支持短连接的请求-响应模式,而GraphQL订阅依赖双向长连接,必须通过WebSocket实现(和你提到的Apollo方案一致)。下面是具体实现步骤和代码示例:
核心思路
GraphQL订阅通常遵循graphql-ws协议,流程为:
- 建立WebSocket连接到服务器的WebSocket端点
- 发送初始化消息(携带认证token)
- 发送订阅请求(包含GraphQL查询)
- 持续监听服务器推送的更新
- 处理连接关闭或错误
选择WebSocket库
推荐使用Boost.Beast(C++17兼容,提供完整的WebSocket实现),也可以选择libwebsockets或uWebSockets。以下示例基于Boost.Beast。
代码实现
基于你现有的TestClient类,新增WebSocket相关逻辑:
1. 更新头文件(TestClient.hpp)
#include <string> #include <list> #include <curlpp/Easy.hpp> #include "jsoncpp/json/reader.h" #include <boost/beast.hpp> #include <boost/asio.hpp> #include <nlohmann/json.hpp> namespace beast = boost::beast; namespace websocket = beast::websocket; namespace net = boost::asio; using tcp = net::ip::tcp; using json = nlohmann::json; class TestClient { public: TestClient(); virtual ~TestClient(); void login(); void subscribe(); protected: std::string sendRequest(const std::list<std::string> &header, const std::string &graphQL); std::string loadFile(std::string filePath); private: curlpp::Easy *m_request = new curlpp::Easy(); Json::Reader m_reader; std::string m_token = ""; std::string m_grapqlLogin; std::string m_grapqlSubscribe; // HTTP和WebSocket配置 const std::string m_HTTP_URL = "http://localhost:4000/graphiql"; const std::string m_WS_HOST = "localhost"; const uint16_t m_WS_PORT = 4000; const std::string m_WS_TARGET = "/graphql"; // WebSocket端点,注意不是/graphiql const std::string m_headerContentType = "Content-Type: application/json"; const std::string m_headerToken = "Authorization:Bearer "; // WebSocket订阅逻辑 void runWebSocketSubscription(); };
2. 更新实现文件(TestClient.cpp)
保留原有的login()和sendRequest()方法,修改subscribe()并新增WebSocket处理逻辑:
void TestClient::subscribe() { if (m_token.empty()) { std::cerr << "错误:请先登录获取token!" << std::endl; return; } runWebSocketSubscription(); } void TestClient::runWebSocketSubscription() { try { // 初始化IO上下文 net::io_context ioc; // 解析服务器地址 tcp::resolver resolver(ioc); auto const results = resolver.resolve(m_WS_HOST, std::to_string(m_WS_PORT)); // 创建WebSocket流并连接 websocket::stream<tcp::socket> ws(ioc); beast::get_lowest_layer(ws).connect(results); // 握手时携带认证token ws.set_option(websocket::stream_base::decorator( [this](websocket::request_type& req) { req.set(beast::http::field::authorization, m_headerToken + m_token); req.set(beast::http::field::user_agent, BOOST_BEAST_VERSION_STRING); })); ws.handshake(m_WS_HOST, m_WS_TARGET); // 1. 发送连接初始化消息(graphql-ws协议要求) json init_msg = { {"type", "connection_init"}, {"payload", {{"Authorization", m_headerToken + m_token}}} }; ws.write(net::buffer(init_msg.dump())); // 接收服务器的连接确认 beast::flat_buffer buffer; ws.read(buffer); std::cout << "连接初始化响应:" << beast::buffers_to_string(buffer.data()) << std::endl; buffer.consume(buffer.size()); // 2. 发送订阅请求 json subscribe_msg = { {"id", "sub_1"}, // 唯一标识该订阅 {"type", "start"}, {"payload", { {"query", m_grapqlSubscribe}, {"variables", {}} // 如有订阅变量可在此添加 }} }; ws.write(net::buffer(subscribe_msg.dump())); // 3. 持续监听服务器推送的更新 std::cout << "开始监听订阅更新..." << std::endl; while (true) { ws.read(buffer); std::string update_str = beast::buffers_to_string(buffer.data()); json update_json = json::parse(update_str); std::cout << "\n收到更新:" << update_json.dump(4) << std::endl; buffer.consume(buffer.size()); // 处理停止信号(可选) if (update_json["type"] == "stop") { std::cout << "订阅已停止" << std::endl; break; } } // 关闭连接 ws.close(websocket::close_code::normal); } catch (const std::exception& e) { std::cerr << "WebSocket错误:" << e.what() << std::endl; } }
关键注意事项
- 端点差异:HTTP请求用
/graphiql,但WebSocket订阅必须连接到服务器的GraphQL WebSocket端点(通常是/graphql),请确认服务器配置。 - 协议规范:howtographql的服务器使用
graphql-ws协议,消息类型必须严格符合规范(connection_init、start、data等)。 - JSON库:示例用nlohmann/json处理JSON,你可以替换为熟悉的JsonCpp,只需调整序列化/反序列化逻辑。
- 异步处理:示例是阻塞式监听,若需要非阻塞或多线程,可结合Boost.Asio的异步API实现。
为什么curlpp无法处理订阅
curlpp仅支持HTTP短连接的请求-响应模式,无法维持长连接进行双向实时通信,而GraphQL订阅依赖WebSocket的长连接特性,因此必须使用WebSocket库替代curlpp处理订阅逻辑。
内容的提问来源于stack exchange,提问作者PhiloLars
相关产品推荐
相关产品推荐

