nodejs 如何设置http 请求的超时时间

场景: 我需要在nodejs中调用一个处理时间较长的接口吗,可能会超过120s。

  nodejs 默认的 http 请求超时时间超过120s,则会返回超时。

问题:

如何修改默认的超时时间呢?
最好是针对某个请求修改,不要影响到其他请求。

Koa示例:

// 这里虚拟一个处理时间较长的 接口
    const timeoutService = function (time) {
    time = time || 5000
    return new Promise((resolve, reject) => {
        try {
            setTimeout(function () {
                let data = [{
                                name: 'Tommy',
                                age: 10
                            }, {
                                name: 'Jupiter',
                                age: 18
                            }];
                resolve(data)
            }, time)
        } catch (e) {
            reject(e)
        }
    }).then(res => {
        return res
    }).catch(e => {
        return e
    })
}

router.get('/list', async (ctx) => {
    // 设置处理过程超过120s
    let data = await timeoutService(121000)
    ctx.status = 200;
    ctx.body = {
        success: true,
        data: data
    };
});

使用nodejs调用

// nodejs 调用
const GetList = (data) => {
  return new Promise((resolve, reject) => {
    let bs = JSON.stringify(data)
    console.log(bs)
    let encode = new Buffer(bs).toString('base64')
    let postData = JSON.stringify({ data: encode})
    var opt = {
        method: 'GET',
        host: 'localhost',
        port: 3100,
        path: '/list',
        headers: {
            'Content-Type': 'application/json',
            'Content-Length': Buffer.byteLength(postData),
            'Accept': 'application/json; charset=utf-8'
        }
    }
    let req = http.request(opt)
    req.on('response', (res) => {
        console.log('状态码:' + res.statusCode)
        console.log('响应头: ' + JSON.stringify(res.headers))
        let body = ''
        res.on('data', (data) => {
          body += data
        })
        res.on('end', () => {
          resolve(body)
        })
    })

    req.on('error', (e) => {
      console.log(e)
      console.error('请求遇到问题:' + e.message)
      reject(e.message)
    })
    req.setNoDelay(0)
    req.write(postData)
    req.end()
  })
}

function getTimeLast(label, startTime) {
    let finishTime = Date.now()
    let last = (finishTime - startTime) / 1000
    console.log(`${label} ${last}`)
}

let startTime = Date.now()
GetList({a: 1}).then(res => {
    console.log(res)
    getTimeLast('成功返回用时:', startTime)
}).catch(e => {
    console.log(e)
    getTimeLast('失败返回用时:', startTime)
}) 

结果返回如下:

{"a":1}
{ Error: socket hang up
    at createHangUpError (_http_client.js:331:15)
    at Socket.socketOnEnd (_http_client.js:423:23)
    at emitNone (events.js:111:20)
    at Socket.emit (events.js:208:7)
    at endReadableNT (_stream_readable.js:1055:12)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickCallback (internal/process/next_tick.js:180:9) code: 'ECONNRESET' }
请求遇到问题:socket hang up
socket hang up
失败返回用时: 120.018

阅读 20.1k
3 个回答

这个问题应该是我没有定位好问题所在。我自己梳理了一下。
timeout 可以理解成耐心值,客户端发送请求时,可以设置自己的timeout。同时服务端也有自己的耐心值,二者互不干涉,二者都有权在超时后丢掉链接。

  • 客户端发送请求时,如果在客户端timeout 时间内,服务端仍没有返回,那么它会终止这个请求。
  • 如果客户端足够耐心(timeout 够大),但中间服务器没有耐心,客户端也会收到一个504 timeout
  • 如果目标服务器在超时后仍未返回,那么链接也会关闭,客户端不会收到返回。

所以确实是可以使用request.setTimeout来设置请求的timeout的,但是这个值不能超过服务器本身最大的限制。比如server.timeout = 5000;即使在setTimeout 中设置6000,仍是不生效的。所以如果瓶颈在与接口服务器的超时限制,修改客户端的超时时间是无济于事的。

request.setTimeout

因为长时间没有响应,客户端认为socket已经断开,而服务端并不认为,让你重用原来的socket。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题