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

原生NodeJS开发Appsync客户端执行queries/mutations时偶发JSON解析错误

问题根因
  • 最核心的问题是你对HTTP响应的流式处理逻辑错误:原生https模块返回的IncomingMessage对象的data事件会在每收到一段数据分片时触发,并非等待全部响应加载完成后才触发。当网络波动、响应体体积较大时,完整响应会被拆成多个分片返回,你直接对单个分片做JSON解析自然会偶发格式错误。
  • 还有两个隐性错误会加剧问题:
    1. 监听的响应错误事件名错误,正确事件名是error不是errors,运行过程中的响应层错误无法被正常捕获,会直接抛出未处理异常
    2. throwOnErrors函数要求接收一个包含query/variables/errors字段的对象参数,你当前调用时传入的是三个零散参数,会导致错误发生时无法正常生成错误信息
修复方案

你需要先累加所有响应分片,等全部响应加载完成后再做JSON解析,同时修正上述隐性问题,修复后的参考代码如下:

var https = require("https");
let AWS = require("aws-sdk");
let urlParse = require("url").URL;
require("dotenv").config();

const throwOnErrors = ({ query, variables, errors }) => {
  if (errors) {
    const errorMessage = `
        query: ${query.substr(0, 100)}

        variables: ${JSON.stringify(variables, null, 4)}

        error: ${JSON.stringify(errors, null, 4)}
        `;
    throw new Error(errorMessage);
  }
};

module.exports = async (
  url,
  credentials,
  query,
  operationName,
  variables = {}
) => {
  
  AWS.config.update({
    region: process.env.AWS_REGION,
    credentials: new AWS.Credentials(
      credentials.accessKeyId,
      credentials.secretAccessKey,
      credentials.sessionToken
    ),
  });

  let endpoint = new urlParse(url).hostname.toString();
  const item = {
    input: variables
  };
  let req = new AWS.HttpRequest(url, process.env.AWS_REGION);
  req.method = "POST";
  req.headers.host = endpoint;
  req.headers["Content-Type"] = "application/json";
  req.body = JSON.stringify({
    query: query,  
    operationName: operationName,
    variables: item
  });

  let signer = new AWS.Signers.V4(req, "appsync", true);
  signer.addAuthorization(AWS.config.credentials, AWS.util.date.getDate());

  const data = await new Promise((resolve, reject) => {
    const httpRequest = https.request({ ...req, host: endpoint }, (result) => {
      // 声明buffer累加响应分片
      let chunks = [];
      // 累加分片
      result.on("data", (chunk) => {
        chunks.push(chunk);
      });

      // 全部响应接收完成后处理
      result.on("end", () => {
        try {
          const responseStr = Buffer.concat(chunks).toString();
          // 可选:先打印responseStr排查非JSON响应的场景,比如网关报错返回的HTML
          const resultdata = JSON.parse(responseStr);
          if (resultdata.errors) {
            // 修正传参格式
            throwOnErrors({ query, variables, errors: resultdata.errors });
            reject(resultdata);
          } else {
            resolve(resultdata);
          }
        } catch (e) {
          // 捕获解析错误,避免直接抛异常
          reject(e);
        }
      });

      // 修正错误事件名
      result.on("error", (err) => {
        reject(err);
      });
    });
    
    // 监听请求层错误
    httpRequest.on("error", (err) => {
      reject(err);
    });

    httpRequest.write(req.body);
    httpRequest.end();
  });

  return data.data
};

如果修复后仍然偶发解析错误,可以在JSON.parse前打印完整的响应字符串,大概率是网关/权限校验失败返回了非JSON格式的错误报文(比如HTML格式的403/503错误页),可以针对性排查签名、权限配置问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 05:45:02