Nodejs求救:http.request请求别的服务器数据时,有时报错err:socket hands up!

Nodejs求救:http.request请求别的服务器数据时,有时报错err:socket hands up!

node.js使用http.request请求别的服务器数据时,有时会报错err:socket hands up ! 当socket hands up 过多时又会报错: unhandled exception:Error: accept EMFILE at errnoException (net.js:769:11) at TCP.onconnection (net.js:1017:24) 直接导致程序必须重启。 求解!设置请求超时时间的时候,当请求超时时候调用abort()或者destroy()释放还是会报错err:socket hands up !


2 回复

Node.js 求助:http.request 请求别的服务器数据时,有时报错 err:socket hang up!

问题描述

在使用 Node.js 的 http.request 方法请求其他服务器的数据时,有时会遇到 err: socket hang up 错误。当这种错误频繁发生时,可能会进一步引发 unhandled exception 错误,例如:

Error: accept EMFILE
    at errnoException (net.js:769:11)
    at TCP.onconnection (net.js:1017:24)

这些错误会导致程序需要重启才能恢复正常运行。

原因分析

socket hang up 错误通常表示客户端与服务器之间的连接被意外关闭了。这可能是由于网络问题、服务器端处理问题或客户端请求过多导致的资源耗尽(如文件描述符过多)。

EMFILE 错误则表示系统打开的文件描述符数量超过了限制。Node.js 在处理大量并发请求时,如果没有正确管理资源,可能会触发这个错误。

解决方案

为了减少这些问题的发生,可以采取以下几种措施:

  1. 设置请求超时:确保在请求超时时及时关闭连接。
  2. 限制并发请求的数量:通过队列或其他机制来控制同时发起的请求数量。
  3. 正确处理错误:确保所有错误都被妥善处理,避免未捕获的异常。

示例代码

以下是一个简单的示例,展示了如何设置请求超时并处理错误:

const http = require('http');

function makeRequest(url, timeout) {
    return new Promise((resolve, reject) => {
        const req = http.request(url, { method: 'GET' }, res => {
            let data = '';
            res.on('data', chunk => data += chunk);
            res.on('end', () => resolve(data));
        });

        req.on('error', err => reject(err));

        // 设置请求超时
        req.setTimeout(timeout, () => {
            req.destroy();
            reject(new Error('Request timed out'));
        });

        req.end();
    });
}

// 使用示例
makeRequest('http://example.com/api/data', 5000) // 超时时间为5秒
    .then(data => console.log(data))
    .catch(err => console.error('Error:', err.message));

在这个示例中,我们创建了一个 makeRequest 函数,该函数接受一个 URL 和一个超时时间作为参数。如果请求在指定的时间内没有完成,则会调用 req.destroy() 来强制关闭请求,并返回一个错误。这样可以避免 socket hang upEMFILE 等问题的发生。


在Node.js中使用http.request时遇到EMFILE错误(如"socket hang up")通常是因为你的应用打开了太多的套接字或文件描述符。这可能是由于没有正确地处理HTTP请求的回调,导致请求未完成时就关闭了进程。

为了处理这个问题,可以采取以下几种策略:

  1. 限制并发连接数:确保不要同时打开太多连接。可以通过使用队列机制来限制并发连接数。
  2. 正确处理请求与响应:确保在请求完成后正确地结束请求和响应对象。
  3. 设置超时并妥善处理:当请求超时时,应该优雅地处理错误而不是简单地调用abort()destroy()

下面提供一个简单的示例,展示如何处理请求并避免socket hang up错误:

const http = require('http');

function makeRequest(url) {
    return new Promise((resolve, reject) => {
        const req = http.request(url, { method: 'GET' }, res => {
            let data = '';
            res.on('data', chunk => data += chunk);
            res.on('end', () => resolve(data));
        });

        req.on('error', error => reject(error));

        // 设置请求超时
        req.setTimeout(5000, () => {
            req.destroy();
            reject(new Error('Request timed out'));
        });

        req.end();
    });
}

async function safeFetch(urls) {
    for (let url of urls) {
        try {
            const response = await makeRequest(url);
            console.log(response);
        } catch (error) {
            console.error(`Failed to fetch ${url}:`, error.message);
        }
    }
}

// 示例URL列表
safeFetch([
    'http://example.com/api/data',
    'http://another.example.com/api/moredata'
]);

上述代码通过将每个请求包装在一个Promise中来确保它们被正确处理,并设置了超时以避免长时间等待。如果请求超时,它将被优雅地取消,而不会导致“socket hang up”错误。

回到顶部