繁体   English   中英

为什么 request.on 数据在 NodeJS 上延迟触发?

[英]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);

前端代码(来自 devtools 的 snipet)

这段代码将上传到/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);
});

现在运行后端代码,然后运行前端代码,我得到一些日志。

日志捕获(截图)

后端日志和前端日志:

日志

后端与前端的时差:

日志和 devtools 计时选项卡之间的时差

结果

查看屏幕截图,我发现日志之间存在两个差异:

  • 第一个,也是最重要的,是前端获取开始和收到后端请求之间的区别,我得到了 1613 毫秒,这与网络定时选项卡中的Resource Scheduling “接近”(1430 毫秒) ,我认为前端获取调用之间发生了更多的事情和节点后端事件,所以我不能直接比较时间:
log.backendReceivedRequest - log.frontEndStart
1613
  • 第二个是后端接收数据的差异,我得到了 578 毫秒,接近网络计时选项卡中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.

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