首页 > 解决方案 > 强制 API 超时时节点 JS 中的套接字挂断错误

问题描述

我在 Node JS (v8.12) 中使用请求模块来调用第三方 API。由于 API 不是很可靠并且由于缺乏更好的选项,我会在 2 秒后超时调用,以防 API 没有响应。但是这样做会产生一个套接字挂起错误。下面是使用的代码和堆栈跟踪

const options = {
    url: resource_url,
    rejectUnauthorized: false,
    timeout: 2000,
    method: 'GET',
    headers: {
        'content-Type': 'application/json',
    }
};

return new Promise(function (resolve, reject) {
    request(options, function (err, res, body) {
        if (!err) {
            resolve(JSON.parse(body.data));                 
        } else {
            if (err.code === 'ETIMEDOUT' || err.code == 'ESOCKETTIMEDOUT') {
                resolve(someOldData);
            } else {
                resolve(someOldData);
            }
        }
    });
});


Error: socket hang up
    at createHangUpError (_http_client.js:331:15)
    at TLSSocket.socketCloseListener (_http_client.js:363:23)
    at scope.activate (<trace-log-base-path>/dd-trace/packages/dd-trace/src/scope/base.js:54:19)
    at Scope._activate (<trace-log-base-path>/dd-trace/packages/dd-trace/src/scope/async_hooks.js:51:14)
    at Scope.activate (<trace-log-base-path>/dd-trace/packages/dd-trace/src/scope/base.js:12:19)
    at TLSSocket.bound (<trace-log-base-path>/dd-trace/packages/dd-trace/src/scope/base.js:53:20)
    at emitOne (events.js:121:20)
    at TLSSocket.emit (events.js:211:7)
    at _handle.close (net.js:554:12)
    at TCP.done [as _onclose] (_tls_wrap.js:356:7)

在做了一些阅读和研究之后,我发现这篇文章指出了一个类似的问题,所以我切换到了 http 模块,正如文章中的一个解决方案中提到的那样。但是切换到 http 模块也没有解决问题。下面是使用 http 和堆栈跟踪的代码实现。

let responseData;
const requestOptions = {
    hostname: resource_host,
    path: resource_path,
    method: 'GET',
    timeout: 2000,
};

return new Promise((resolve, reject) => {
    const requestObject = http.request(requestOptions, (responseObj) => {
        responseObj.setEncoding('utf8');
        responseObj.on('data', (body) => {          
           responseData = body;
        });

        responseObj.on('end', () => {
            resolve(responseData);
        });
    });

    requestObject.on('error', (err) => {
        responseData = someOldData;
        resolve(responseData);
    });

    requestObject.on('timeout', () => {
        responseData = someOldData;
        requestObject.abort();
    });

    requestObject.end();
});

Error: socket hang up
    at connResetException (internal/errors.js:608:14)
    at Socket.socketCloseListener (_http_client.js:400:25)
    at <trace-log-base-path>/dd-trace/packages/dd-trace/src/scope/base.js:54:19
    at Scope._activate (<trace-log-base-path>/dd-trace/packages/dd-trace/src/scope/async_hooks.js:51:14)
    at Scope.activate (<trace-log-base-path>/dd-trace/packages/dd-trace/src/scope/base.js:12:19)
    at Socket.bound (<trace-log-base-path>/dd-trace/packages/dd-trace/src/scope/base.js:53:20)
    at Socket.emit (events.js:322:22)
    at Socket.EventEmitter.emit (domain.js:482:12)
    at TCP.<anonymous> (net.js:672:12)

我通过网络浏览了多个 SO 帖子和各种其他资源,但我无法解决这个问题。

可能是因为第三方,因为我还尝试通过创建一个虚拟服务器来重现该问题,该服务器在请求被触发后休眠一段时间并超时该请求但无法重现该问题。

我将非常感谢在这方面的任何帮助。

标签: node.jssocketsnode-modulesnode-requestnode-https

解决方案


使用 http 模块时删除超时事件块中的requestObject.abort()可解决此问题。


推荐阅读