首页 > 解决方案 > Node.js Promise 只返回它应该返回的一小部分

问题描述

我有一个 Promise,它曾经等待接收完整的 JSON 字符串,但现在它只返回 JSON 字符串的一小部分。我目前正在使用 Shopify API 来创建客户,这就是响应字符串的样子:

{
  "customer": {
    "id": 1073339461,
    "email": "steve.lastnameson@example.com",
    "accepts_marketing": false,
    "created_at": "2019-04-18T15:42:33-04:00",
    "updated_at": "2019-04-18T15:42:33-04:00",
    "first_name": "Steve",
    "last_name": "Lastnameson",
    "orders_count": 0,
    "state": "disabled",
    "total_spent": "0.00",
    "last_order_id": null,
    "note": null,
    "verified_email": true,
    "multipass_identifier": null,
    "tax_exempt": false,
    "phone": "+15142546011",
    "tags": "",
    "last_order_name": null,
    "currency": "USD",
    "addresses": [
      {
        "id": 1053317291,
        "customer_id": 1073339461,
        "first_name": "Mother",
        "last_name": "Lastnameson",
        "company": null,
        "address1": "123 Oak St",
        "address2": null,
        "city": "Ottawa",
        "province": "Ontario",
        "country": "Canada",
        "zip": "123 ABC",
        "phone": "555-1212",
        "name": "Mother Lastnameson",
        "province_code": "ON",
        "country_code": "CA",
        "country_name": "Canada",
        "default": true
      }
    ],
    "accepts_marketing_updated_at": "2019-04-18T15:42:33-04:00",
    "marketing_opt_in_level": null,
    "admin_graphql_api_id": "gid://shopify/Customer/1073339461",
    "default_address": {
      "id": 1053317291,
      "customer_id": 1073339461,
      "first_name": "Mother",
      "last_name": "Lastnameson",
      "company": null,
      "address1": "123 Oak St",
      "address2": null,
      "city": "Ottawa",
      "province": "Ontario",
      "country": "Canada",
      "zip": "123 ABC",
      "phone": "555-1212",
      "name": "Mother Lastnameson",
      "province_code": "ON",
      "country_code": "CA",
      "country_name": "Canada",
      "default": true
    }
  }
}

然而,这就是我真正得到的回报:

{"customer

我拥有的 Promise 在一个函数中,该函数应该在继续之前等待结果,但是正如您所看到的,它由于某种原因严重切断了字符串。

从我第一次编写函数开始的过去 6 个月里,它一直没有问题。今天是它开始这样做的第一天。

这是函数(AWS Lambda 上的节点 8.10):

async function makeCall(path, method, data = '', again = true) {

    return new Promise((resolve, reject) => {
        const bearer = "Basic " + Buffer.from(shopKey + ":" + shopPass).toString('base64');
        const options = {
            host: shopURL,
            path: path,
            method: method,
            headers: {
                "Content-Type" : "application/json",
                "Authorization" : bearer
            }
        };


        const req = http.request(options, (res) => {


        });

        req.on('response', function(res){

            res.on('data', function(chunk){
                const body  = chunk.toString('utf8');
                console.log('chunk', chunk);
                console.log(body);
                resolve(JSON.parse(body));
            });

        });

        req.on('error', (e) => {
            if (again){
                setTimeout(makeCall(path, method, data, again = false), 3000);
            } else {
                reject(e.message);
            }

        });

        // send the request
        req.write(JSON.stringify(data));
        req.end();
    });

}

这是我调用上述函数的函数:

const customer = await makeCall(path, method, data);

标签: javascriptnode.jsaws-lambda

解决方案


我认为问题在于您进行分块的方式。请求可能会逐个向您发送数据,因此您需要将代码更改为:

async function makeCall(path, method, data = '', again = true) {
  return new Promise((resolve, reject) => {
    const bearer = "Basic " + Buffer.from(shopKey + ":" + shopPass).toString('base64');
    const options = {
      host: shopURL,
      path: path,
      method: method,
      headers: {
        "Content-Type" : "application/json",
        "Authorization" : bearer
      }
    };

    let body = '';
    const req = http.request(options, (res) => {
      // Here we are potentially getting chunks of data that we are
      // adding to the main result "body"
      res.on('data', function(chunk){
        body += chunk;
      });
      // Once the request ends we can resolve with the result
      res.on('end', function() {
        resolve(JSON.parse(body));
      });
    });

    req.on('error', (e) => {
      if (again){
        // Updated so that it forwards on the response/error,
        // and only gets called after the timeout
        setTimeout(() => makeCall(path, method, data, false).then(resolve).catch(reject), 3000);
      } else {
        reject(e.message);
      }
    });

    // send the request
    req.write(JSON.stringify(data));
    req.end();
  });
};

推荐阅读