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

传入字符串变量与直接传字符串值调用API结果不同的问题

问题

将字符串变量作为参数调用API时返回“invalid input data”错误,但复制变量的值直接传入API却能正常运行,推测该问题与编译器对转义引号"的处理行为有关。

API定义

@PostMapping(value = "/data/v0/query", consumes = {MediaType.APPLICATION_JSON_VALUE})
JsonNode mecGraphQLQuery(
        @RequestHeader(HttpHeaders.AUTHORIZATION) String bearerToken,
        @RequestBody String query
);

API期望的query参数格式

"{ \"query\": \"query getMecFeedbackDataByDateRange( $filter: Filter, $numPerPage: Int!, $orderBy: [RecordOrder] ) { feedback( filter: $filter, first: $numPerPage, orderBy: $orderBy ) { nodes { e_bp_digital_uuid_txt: fieldValue(fieldId: \\\"e_bp_digital_uuid_txt\\\") responsedate: fieldValue(fieldId: \\\"e_responsedate\\\") } totalCount pageInfo { endCursor hasNextPage } } }\", \"variables\": { \"filter\": { \"and\": [ { \"fieldIds\": [ \"e_responsedate\" ], \"gte\": \"2023-08-22 01:52:15\" }, { \"fieldIds\": [ \"e_responsedate\" ], \"lte\": \"2023-08-24 01:57:15\" } ] }, \"numPerPage\": 1000, \"orderBy\": [ { \"fieldId\": \"e_responsedate\", \"direction\": \"DESC\" } ] }}"

生成query的代码

public String getMecFeedbackDataByDateRangeQuery(String host, String mecAccessToken, String fromDate, String toDate, Set<MecField> fieldNames) {
        Preconditions.checkArgument(!fieldNames.isEmpty(), "List of fields must not be empty!");
        Map<String,Object> velocityContext = new HashMap<>();
        velocityContext.put("fromDate", fromDate);
        velocityContext.put("toDate", toDate);
        velocityContext.put("fieldNames", fieldNames);
        String query = generateGraphQLQuery(velocityContext, "/graphQLTemplates/feedbackDataByDateRange.vm");
        log.info("MEC GraphQL Query: " + query);
        return query.replace("\n", "");
}

String query = graphQLFeedbackClient.getMecFeedbackDataByDateRangeQuery(mecIntegrationConfiguration.getHostHeader(), mecAccessToken, fromDateAsString, toDateAsString, fieldNames);

Velocity模板文件/graphQLTemplates/feedbackDataByDateRange.vm内容

"{
    \"query\":
      \"query getMecFeedbackDataByDateRange( $filter: Filter, $numPerPage: Int!, $orderBy: [RecordOrder] ) {
        feedback(
            filter: $filter,
            first: $numPerPage,
            orderBy: $orderBy
        ) {
          nodes {
            #foreach ($field in $fieldNames)
              $field.getField(): fieldValue(fieldId: \\\"$field.getField()\\\")
            #end
            responsedate: fieldValue(fieldId: \\\"e_responsedate\\\")
          }
          totalCount
          pageInfo {
           endCursor
           hasNextPage
          }
        }
      }\",
    \"variables\":
    {
      \"filter\": {
        \"and\": [
          {
            \"fieldIds\": [
              \"e_responsedate\"
            ],
            \"gte\": \"$fromDate\"
          },
          {
            \"fieldIds\": [
              \"e_responsedate\"
            ],
            \"lte\": \"$toDate\"
          }
        ]
      },
    \"numPerPage\": 1000,
      \"orderBy\": [
        {
          \"fieldId\": \"e_responsedate\",
          \"direction\": \"DESC\"
        }
      ]
    }
}"

调用代码对比

  • 传变量时报错:
mecApisGraphQLClient.mecGraphQLQuery(MecGraphQLClient.BEARER_PREFIX + mecAccessToken, query)
  • 直接传复制的值时正常:
mecApisGraphQLClient.mecGraphQLQuery(MecGraphQLClient.BEARER_PREFIX + mecAccessToken, "{ \"query\": \"query getMecFeedbackDataByDateRange( $filter: Filter, $numPerPage: Int!, $orderBy: [RecordOrder] ) { feedback( filter: $filter, first: $numPerPage, orderBy: $orderBy ) { nodes { e_bp_digital_uuid_txt: fieldValue(fieldId: \\\"e_bp_digital_uuid_txt\\\") responsedate: fieldValue(fieldId: \\\"e_responsedate\\\") } totalCount pageInfo { endCursor hasNextPage } } }\", \"variables\": { \"filter\": { \"and\": [ { \"fieldIds\": [ \"e_responsedate\" ], \"gte\": \"2023-08-22 01:52:15\" }, { \"fieldIds\": [ \"e_responsedate\" ], \"lte\": \"2023-08-24 01:57:15\" } ] }, \"numPerPage\": 1000, \"orderBy\": [ { \"fieldId\": \"e_responsedate\", \"direction\": \"DESC\" } ] }}");

通过DiffUtils.diff得到差异对比结果(见附图)。


解决方案

问题根源

核心问题是Velocity生成的字符串存在多余的包裹层级和转义处理错误:

  1. 直接传入的字符串是Java代码字面量,编译器会自动处理双重转义(比如\\\"最终会解析为\");
  2. 但Velocity模板中手动添加的最外层双引号会被直接输出,导致整个query变成了带额外引号包裹的字符串,而API期望的是纯JSON内容,不需要这层多余的引号。

修复步骤

  1. 修改Velocity模板,移除最外层双引号
    删除模板开头的"{和结尾的}",因为这层引号是Java字面量的语法需要,不是实际JSON的一部分。修改后的模板如下:
    {
        \"query\":
          \"query getMecFeedbackDataByDateRange( $filter: Filter, $numPerPage: Int!, $orderBy: [RecordOrder] ) {
            feedback(
                filter: $filter,
                first: $numPerPage,
                orderBy: $orderBy
            ) {
              nodes {
                #foreach ($field in $fieldNames)
                  $field.getField(): fieldValue(fieldId: \\\"$field.getField()\\\")
                #end
                responsedate: fieldValue(fieldId: \\\"e_responsedate\\\")
              }
              totalCount
              pageInfo {
               endCursor
               hasNextPage
              }
            }
          }\",
        \"variables\":
        {
          \"filter\": {
            \"and\": [
              {
                \"fieldIds\": [
                  \"e_responsedate\"
                ],
                \"gte\": \"$fromDate\"
              },
              {
                \"fieldIds\": [
                  \"e_responsedate\"
                ],
                \"lte\": \"$toDate\"
              }
            ]
          },
        \"numPerPage\": 1000,
          \"orderBy\": [
            {
              \"fieldId\": \"e_responsedate\",
              \"direction\": \"DESC\"
            }
          ]
        }
    }
    
  2. 验证生成的字符串格式
    生成后通过日志打印query,确认内容和直接传入的字面量(去掉Java语法转义后的纯JSON)完全一致。
  3. 长期优化方案
    避免用字符串模板拼接JSON,推荐使用Jackson/Gson等JSON库构建实体类后序列化:
    • 定义Query、Variables对应的实体类;
    • 填充实体类数据;
    • 将实体类序列化为JSON字符串传入API,彻底规避转义错误。

内容的提问来源于stack exchange,提问作者aaa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 23:32:15