简体   繁体   English

在 node.js 上传应用程序中 60 秒后连接重置

[英]Connection resets after 60 seconds in node.js upload application

I've written an application in node.js consisting of a server and a client for storing/uploading files.我在 node.js 中编写了一个应用程序,它由一个服务器和一个客户端组成,用于存储/上传文件。

For reproduction purposes, here's a proof of concept using a null write stream in the server and a random read stream in the client.出于再现目的,这里是使用服务器中的空写入流和客户端中的随机读取流的概念证明。

Using node.js 12.19.0 on Ubuntu 18.04.在 Ubuntu 18.04 上使用 node.js 12.19.0。 The client depends on node-fetch v2.6.1.客户端依赖于 node-fetch v2.6.1。

The issue I have is after 60 seconds the connection is reset and haven't found a way to make this work.我遇到的问题是60 秒后连接被重置,但还没有找到使这项工作的方法。

Any ideas are appreciated.任何想法表示赞赏。

Thank you.谢谢你。

testServer.js

// -- DevNull Start --
var util         = require('util')
  , stream       = require('stream')
  , Writable     = stream.Writable
  , setImmediate = setImmediate || function (fn) { setTimeout(fn, 0) }
  ;
util.inherits(DevNull, Writable);
function DevNull (opts) {
  if (!(this instanceof DevNull)) return new DevNull(opts);
  opts = opts || {};
  Writable.call(this, opts);
}
DevNull.prototype._write = function (chunk, encoding, cb) {
  setImmediate(cb);
}
// -- DevNull End --
const http = require('http');
const server = http.createServer();
server.on('request', async (req, res) => {
  try {
    req.socket.on('end', function() { 
      console.log('SOCKET END: other end of the socket sends a FIN packet');
    });
    req.socket.on('timeout', function() { 
      console.log('SOCKET TIMEOUT');
    });
    req.socket.on('error', function(error) { 
      console.log('SOCKET ERROR: ' + JSON.stringify(error));
    });
    req.socket.on('close', function(had_error) { 
      console.log('SOCKET CLOSED. IT WAS ERROR: ' + had_error);
    });
    const writeStream = DevNull();
    const promise = new Promise((resolve, reject) => {
      req.on('end', resolve);
      req.on('error', reject);
    });
    req.pipe(writeStream);
    await promise;
    res.writeHead(200);
    res.end('OK');
  } catch (err) {
    res.writeHead(500);
    res.end(err.message);
  }
});
server.listen(8081)
  .on('listening', () => { console.log('Listening on port', server.address().port); });

testClient.js

// -- RandomStream Start --
var crypto = require('crypto');
var stream = require('stream');
var util = require('util');
var Readable = stream.Readable;
function RandomStream(length, options) {
  // allow calling with or without new
  if (!(this instanceof RandomStream)) {
    return new RandomStream(length, options);
  }
  // init Readable
  Readable.call(this, options);
  // save the length to generate
  this.lenToGenerate = length;
}
util.inherits(RandomStream, Readable);
RandomStream.prototype._read = function (size) {
  if (!size) size = 1024; // default size
  var ready = true;
  while (ready) { // only cont while push returns true
    if (size > this.lenToGenerate) { // only this left
      size = this.lenToGenerate;
    }
    if (size) {
      ready = this.push(crypto.randomBytes(size));
      this.lenToGenerate -= size;
    }
    // when done, push null and exit loop
    if (!this.lenToGenerate) {
      this.push(null);
      ready = false;
    }
  }
};
// -- RandomStream End --
const fetch = require('node-fetch');
const runSuccess = async () => { // Runs in ~35 seconds
  const t = Date.now();
  try {
    const resp = await fetch('http://localhost:8081/test', {
      method: 'PUT',
      body: new RandomStream(256e6) // new RandomStream(1024e6)
    });
    const data = await resp.text();
    console.log(Date.now() - t, data);
  } catch (err) {
    console.warn(Date.now() - t, err);
  }
};
const runFail = async () => { // Fails after 60 seconds
  const t = Date.now();
  try {
    const resp = await fetch('http://localhost:8081/test', {
      method: 'PUT',
      body: new RandomStream(1024e6)
    });
    const data = await resp.text();
    console.log(Date.now() - t, data);
  } catch (err) {
    console.warn(Date.now() - t, err);
  }
};
// runSuccess().then(() => process.exit(0));
runFail().then(() => process.exit(0));

I tried (unsuccessfully) to reproduce what you are seeing based on your code example.我尝试(未成功)根据您的代码示例重现您所看到的内容。 Neither the success call is completing in ~35 seconds nor is the error being thrown in 60 seconds.成功调用既没有在大约 35 秒内完成,也没有在 60 秒内抛出错误。

However, that being said, I think what is happening here is that your client is terminating the request.但是,话虽如此,我认为这里发生的事情是您的客户正在终止请求。 You can increase the timeout by adding a httpAgent to the fetch PUT call.您可以通过向fetch PUT 调用添加httpAgent来增加超时时间。 You can then set a timeout in the httpAgent .然后,您可以在httpAgent设置超时。

const http = require('http');

...

const runFail = async () => { // Fails after 60 seconds
  const t = Date.now();
  try {
    const resp = await fetch('http://localhost:8081/test', {
      method: 'PUT',
      body: new RandomStream(1024e6),
      agent: new http.Agent({ keepAlive: true, timeout: 300000 })
    });
    const data = await resp.text();
    console.log(Date.now() - t, data);
  } catch (err) {
    console.warn(Date.now() - t, err);
  }
};

See the fetch docs for adding a custom http(s) agent here请参阅获取文档以在此处添加自定义 http(s) 代理

See options for creating http(s) agent here在此处查看用于创建 http(s) 代理的选项

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM