[英]Why is request.on data firing with a delay on NodeJS?
有一个简单的 Web 服务器可以接受数据。 下面的示例代码。
这个想法是实时跟踪有多少数据进入服务器并立即通知客户端。 如果您发送少量数据,则一切正常,但如果您发送的数据大小超过 X,则服务器上的 on.data 事件会以巨大的延迟触发。 我可以看到数据已经传输了 5 秒,但是 on.data 事件没有触发。 on.data 事件似乎只有在数据完全上传到服务器时才会触发,这就是为什么它适用于小数据 (~2..20Mb),但对于大数据 (50..200Mb) 则效果不佳。 或者可能是由于某种缓冲..? 你有什么建议为什么 on.data 触发延迟以及如何解决它?
const app = express();
const port = 3000;
// PUBLIC API
// upload file
app.post('/upload', function (request, response) {
request.on('data', chunk => {
// message appears with delay
console.log('upload on data', chunk.length);
// send message to the client about chunk.length
});
response.send({
message: `Got a POST request ${request.headers['content-length']}`
});
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
域名注册地址:
您遇到的延迟可能是来自浏览器的Resource scheduling
Queueing
。
我用express做了一些测试,然后我发现它使用http来处理请求/响应,所以我使用了一个原始的http服务器监听器来测试这个场景,它有相同的情况。
此代码基于 Node 事务示例示例,将创建一个 http 服务器并在 3 种情况下提供时间日志:
data
事件触发时end
事件触发时const http = require('http');
var firstByte = null;
var server = http.createServer((request, response) => {
const { headers, method, url } = request;
let body = [];
request.on('error', (err) => {
}).on('data', (chunk) => {
if (!firstByte) {
firstByte = Date.now();
console.log('received first byte at: ' + Date.now());
}
}).on('end', () => {
console.log('end receive data at: ' + Date.now());
// body = Buffer.concat(body).toString();
// At this point, we have the headers, method, url and body, and can now
// do whatever we need to in order to respond to this request.
if (url === '/') {
response.statusCode = 200;
response.setHeader('Content-Type', 'text/html');
response.write('<h1>Hello World</h1>');
}
firstByte = null;
response.end();
});
console.log('received a request at: ' + Date.now());
});
server.listen(8083);
这段代码将上传到/upload
一些数组数据,我之前用随机字节填充了数组,但后来我删除并看到它对我的计时日志没有任何影响,所以是的..现在上传内容只是一个 0 的数组。
console.log('building data');
var view = new Uint32Array(new Array(5 * 1024 * 1024));
console.log('start sending at: ' + Date.now());
fetch("/upload", {
body: view,
method: "post"
}).then(async response => {
const text = await response.text();
console.log('got response: ' + text);
});
现在运行后端代码,然后运行前端代码,我得到一些日志。
后端日志和前端日志:
后端与前端的时差:
查看屏幕截图,我发现日志之间存在两个差异:
Resource Scheduling
“接近”(1430 毫秒) ,我认为前端获取调用之间发生了更多的事情和节点后端事件,所以我不能直接比较时间:log.backendReceivedRequest - log.frontEndStart
1613
Request sent
(585 毫秒):log.backendReceivedAllData - log.backendReceivedFirstData
578
我还更改了前端代码以发送不同大小的数据,并且网络计时选项卡仍然与日志匹配
对我来说仍然未知的是......为什么谷歌浏览器正在排队我的fetch
因为我不再运行任何请求并且不使用服务器/主机的带宽? 我阅读了排队的条件但没有找到原因,可能是在磁盘上分配资源,但不确定: https : //developer.chrome.com/docs/devtools/network/reference/#timing-explanation
参考:
https://nodejs.org/es/docs/guides/anatomy-of-an-http-transaction/ https://developer.chrome.com/docs/devtools/network/reference/#timing-explanation
我发现了一个问题。 它在nginx配置中。 Nginx 的设置就像一个反向代理。 默认情况下启用代理请求缓冲,因此 nginx 首先获取整个请求正文,然后才将其转发给 nodejs,这就是我看到延迟的原因。
https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_request_buffering
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.