You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何验证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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:44:30