javascript - 在 node.js 上传应用程序中 60 秒后连接重置
问题描述
我在 node.js 中编写了一个应用程序,由一个服务器和一个用于存储/上传文件的客户端组成。
出于复制目的,这里是使用服务器中的空写入流和客户端中的随机读取流的概念证明。
在 Ubuntu 18.04 上使用 node.js 12.19.0。客户端依赖于 node-fetch v2.6.1。
我遇到的问题是60 秒后连接被重置并且还没有找到一种方法来完成这项工作。
任何想法表示赞赏。
谢谢你。
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));
解决方案
我尝试(未成功)根据您的代码示例重现您所看到的内容。成功调用既不会在约 35 秒内完成,也不会在 60 秒内引发错误。
但是,话虽如此,我认为这里发生的是您的客户正在终止请求。您可以通过在PUT 调用中添加一个httpAgent
来增加超时。fetch
然后,您可以在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);
}
};
请参阅获取文档以在此处添加自定义 http(s) 代理
在此处查看创建 http(s) 代理的选项
推荐阅读
- django - 在 Django 中设置初始字段
- javascript - 我的护照本地策略出现错误,提示未定义密码
- java - 图形数据的查询修改
- oracle - 从 2 个表中选择数据并匹配 2 个字段(oracle sql developer)
- angular - 已安装 Angular 版本 ~7.1.0 想要安装版本 4
- arrays - Postgres - 如何使用自定义数据类型数组创建自定义数据类型
- c# - 使用代理,仅适用于特定的服务器证书
- jenkins - Jenkins 错误无法生成脚本文件
- java - 读取配置文件返回 null
- python - 根据列定位从两个数据框中获取数字的百分比变化