如何验证RapidJSON文档子集?JSON-RPC按方法匹配Schema的实现疑问
针对JSON-RPC不同Method的RapidJSON Schema验证实现方案
我之前做JSON-RPC服务的时候也碰到过一模一样的需求——不同方法的参数结构差异很大,必须用对应的Schema做针对性验证。你的思路完全没问题,用方法名作为键来映射对应的SchemaDocument是最直接的方案,下面我给你细化下具体实现步骤和需要注意的坑:
核心实现步骤
1. 准备各Method对应的JSON Schema
首先给每个method定义专属的Schema,比如你示例里的increment方法,对应的Schema可以这样写(确保params是包含一个带count整数的对象数组):
{ "type": "array", "items": [ { "type": "object", "properties": { "count": { "type": "integer", "minimum": 0 } }, "required": ["count"] } ] }
2. 初始化Schema映射表
这里要注意RapidJSON的SchemaDocument不支持拷贝构造,所以不能直接把它存在unordered_map的值里,推荐用std::unique_ptr来管理,避免内存问题和拷贝错误:
#include <rapidjson/schema.h> #include <unordered_map> #include <memory> #include <cstdio> // 全局或类内的Schema映射表,用unique_ptr存储SchemaDocument std::unordered_map<std::string, std::unique_ptr<rapidjson::SchemaDocument>> methodSchemas; void initRpcSchemas() { // 初始化increment方法的Schema const char* incrementSchemaStr = R"( { "type": "array", "items": [ { "type": "object", "properties": { "count": { "type": "integer", "minimum": 0 } }, "required": ["count"] } ] } )"; rapidjson::Document schemaDoc; if (schemaDoc.Parse(incrementSchemaStr).HasParseError()) { printf("Failed to parse increment schema: %s\n", rapidjson::GetParseError_En(schemaDoc.GetParseError())); return; } // 用make_unique创建SchemaDocument并插入映射表 methodSchemas["increment"] = std::make_unique<rapidjson::SchemaDocument>(schemaDoc); // 可以继续添加其他method的Schema,比如decrement、reset等 }
3. 解析并验证JSON-RPC消息
先验证消息的基础JSON-RPC结构(必须包含合法的method字段),再根据method找到对应的Schema验证params:
bool validateRpcRequest(const rapidjson::Document& rpcDoc) { // 第一步:验证JSON-RPC基础结构 if (!rpcDoc.HasMember("method") || !rpcDoc["method"].IsString()) { printf("Invalid RPC message: missing or invalid 'method' field\n"); return false; } const std::string method = rpcDoc["method"].GetString(); auto schemaIter = methodSchemas.find(method); if (schemaIter == methodSchemas.end()) { printf("No schema found for method: %s\n", method.c_str()); return false; // 或者根据需求允许未定义的方法 } // 第二步:验证params字段 if (!rpcDoc.HasMember("params")) { printf("RPC message missing 'params' field\n"); return false; } // 创建Schema验证器并执行验证 rapidjson::SchemaValidator validator(*(schemaIter->second)); if (!rpcDoc["params"].Accept(validator)) { // 验证失败时输出详细错误信息 rapidjson::StringBuffer errSb; validator.GetInvalidSchemaPointer().StringifyUriFragment(errSb); printf("Invalid schema at: %s\n", errSb.GetString()); printf("Failed keyword: %s\n", validator.GetInvalidSchemaKeyword()); errSb.Clear(); validator.GetInvalidInstancePointer().StringifyUriFragment(errSb); printf("Invalid params at: %s\n", errSb.GetString()); return false; } return true; }
关键注意事项
- SchemaDocument的生命周期:
SchemaDocument会内部存储Schema的内容,初始化后原解析用的Document可以安全销毁,用unique_ptr管理是最稳妥的方式。 - 动态添加Schema:如果需要在运行时新增method对应的Schema,直接用
methodSchemas.emplace(methodName, std::make_unique<rapidjson::SchemaDocument>(newSchemaDoc))即可。 - 错误处理:
SchemaValidator提供了详细的错误定位信息,在调试和生产环境排障时非常有用,建议不要忽略这些信息。
内容的提问来源于stack exchange,提问作者evadeflow
相关产品推荐
相关产品推荐

