JSON HTTP 请求的 Promise 中的 .catch 子句未捕获的错误

Uncaught errors by .catch clause in Promise for JSON HTTP request

我有这个功能可以从 API 端点收集 JSON 数据:

  export const getDataAPI = (token_id) => {
  const url = `https://api.url.com/tokens/` + token_id;
  const options = {method: 'GET', headers: {Accept: 'application/json'}};
  const request = fetch(url, options)
    .then(response => { if (response.status === 200) {
        return response.json();
      } else if ([404, 429, 500].includes(response.status)) {
        return response.status;
      } else {
        return response.json()
          .then(json => {
            console.log("Error: getDataAPI response status", response.status);
            throw json;
          })
      }
    })
    .catch(error => { throw error; });
  return Promise.resolve(request);
};

我用这个功能收集了超过130万条记录。我想捕捉任何意想不到的问题,这样我就可以优雅地暂停几秒钟,然后重试。但是我遇到了 2 个未发送到 .catch 子句的错误。即使 response 为空/空/未定义,我也希望至少能看到 console.log("Error: getDataAPI response status", response.status); 的输出 这些错误每个只发生一次。

undefined:1

SyntaxError: Unexpected end of JSON input
    at JSON.parse (<anonymous>)
    at Response.json (file:///home/user/node_modules/node-fetch/src/body.js:149:15)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async file:///home/user/path/to/file.mjs:94:20
file:///home/user/node_modules/node-fetch/src/index.js:108
            reject(new FetchError(`request to ${request.url} failed, reason: ${error.message}`, 'system', error));
                   ^

FetchError: request to https://api.url.com/tokens/29727608 failed, reason: read ECONNRESET
    at ClientRequest.<anonymous> (file:///home/user/node_modules/node-fetch/src/index.js:108:11)
    at ClientRequest.emit (node:events:526:28)
    at TLSSocket.socketErrorListener (node:_http_client:442:9)
    at TLSSocket.emit (node:events:526:28)
    at emitErrorNT (node:internal/streams/destroy:157:8)
    at emitErrorCloseNT (node:internal/streams/destroy:122:3)
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {
  type: 'system',
  errno: 'ECONNRESET',
  code: 'ECONNRESET',
  erroredSysCall: 'read'
}
  1. 我不明白为什么这些错误没有被函数捕获。有人可以解释一下吗?

  2. 我怎样才能修复这个函数,让它也能捕捉到这类错误?

  3. 我应该寻找什么输出来识别这些错误,SyntaxErrorFetchError?例如,是否有用于监视错误代码的变量?

I would expect at least to see the output of console.log("Error: getDataAPI response status", response.status);

该代码不在 catch 子句中,它在 then 子句中。

return response.json()
          .then(json => {
            console.log("Error: getDataAPI response status", response.status);
            throw json;
          })

您的 catch 只是重新抛出:

.catch(error => { throw error; });

这会给你一个未捕获的错误。

您需要 log/handle 捕获错误,而不是 then 子句:

 export const getDataAPI = (token_id) => {
  const url = `https://api.url.com/tokens/` + token_id;
  const options = {method: 'GET', headers: {Accept: 'application/json'}};
  const request = fetch(url, options)
    .then(response => { if (response.status === 200) {
        return response.json();
      } else if ([404, 429, 500].includes(response.status)) {
        return response.status;
      } else {
        console.log("Error: getDataAPI response status", response.status);
        // you can swallow the error here if you want, or try to parse it anyway
        return response.json()
      }
    })
    .catch(error => { 
       console.log('Handling error', error);
       throw error;
    });

  // wrapping the request in a Promise.resolve is also unnecessary 
  // return Promise.resolve(request);
  return request;
};
 

在 xdumaine 的帮助下,我能够弄清楚我做错了什么。

  1. 这些错误没有触发 console.log 报告,因为它们甚至在可以组成 JSON 字符串之前就已经出现了。

  2. 函数正在捕获错误,只是没有对它们做任何事情。我发现 this page 有助于更好地理解和测试它。作为演示,这是一种创建错误并确认 .catch() 子句正在处理它的方法:

export const getDataAPI = (token_id) => {
  const url = `https://api.url.com/tokens/` + token_id;
  const options = {method: 'GET', headers: {Accept: 'application/json'}};
  const request = fetch(url, options)
    .then(response => { 
        throw new SyntaxError('Hello', 'someFile.js', 10);
        if (response.status === 200) {
        return response.json();
      } else if ([404, 429, 500].includes(response.status)) {
        return response.status;
      } else {
        return response.json()
          .then(json => {
            console.log("Error: getDataAPI response status", response.status);
            throw json;
          })
      }
    })
    .catch(error => { 
      console.log('Caught error', error.name);
      throw error; 
      });
  return request;
};
  1. 如上面链接的页面所示,error.name 包含错误的名称。