首页 > 解决方案 > 进行查询/突变时 Vanilla NodeJS Appsync 客户端错误

问题描述

我正在尝试使用签署和发送请求的普通 nodejs 客户端来访问我的 Appsync GraphQL 端点。它是:

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) => {
      result.on("data", (data) => {
        
        resultdata = JSON.parse(data.toString());
        if (resultdata.errors != null) {
          throwOnErrors(query, variables, data);
          reject(resultdata);
        } else {
          resolve(resultdata);
        }
      });

      result.on("errors", (data) => {
        reject(() => {
          throwOnErrors(query, variables, data)
          return JSON.parse(data.toString())
        });
      });
    });
    
    httpRequest.write(req.body);
    httpRequest.end();
  });

  return data.data
};

不幸的是,有时,响应确实会被拒绝,并且错误总是如下所示:

SyntaxError: Unexpected token , in JSON at position 0
        at JSON.parse (<anonymous>)

      56 |       result.on("data", (data) => {
      57 |         
    > 58 |         resultdata = JSON.parse(data.toString());
         |                           ^
      59 |         if (resultdata.errors != null) {
      60 |           throwOnErrors(query, variables, data);
      61 |           reject(resultdata);

      at IncomingMessage.<anonymous> (_tests/lib/graphql.js:58:27)

我真的不知道如何解决这个问题,因为有时承诺会得到解决,有时不会。

你们有什么建议给我吗?

提前致谢!

标签: node.jsjsonamazon-web-servicesgraphqlaws-appsync

解决方案


你的'data'回调可以运行多次,result是一个流,所以

const httpRequest = https.request({ ...req, host: endpoint }, (result) => {
  result.on("data", (data) => {
    
    resultdata = JSON.parse(data.toString());
    if (resultdata.errors != null) {
      throwOnErrors(query, variables, data);
      reject(resultdata);
    } else {
      resolve(resultdata);
    }
  });

  result.on("errors", (data) => {
    reject(() => {
      throwOnErrors(query, variables, data)
      return JSON.parse(data.toString())
    });
  });
});

需要更像

const httpRequest = https.request({ ...req, host: endpoint }, (response) => {
  const chunks = [];
  response.on("data", (data) => { chunks.push(data); });
  response.on("end", () => {        
    resultdata = JSON.parse(Buffer.concat(chunks).toString());
    if (resultdata.errors != null) {
      throwOnErrors(query, variables, data);
      reject(resultdata);
    } else {
      resolve(resultdata);
    }
  });
  response.on("error", err => {
    reject(() => {
      throwOnErrors(query, variables, data)
      return JSON.parse(data.toString())
    });
  });
});

推荐阅读