为什么 Node.JS HTTP 服务器在代理后面无法正常工作?

问题描述 投票:0回答:1

我需要在 Node.JS 中实现一个 HTTP 服务器,使用内置的

http
模块,该模块将从文件系统提供一个大文件。但是,我遇到了一个问题,我的解决方案仅在直接使用时才有效。当它放在 Nginx 反向代理后面时它不起作用。 我当前的实现(示例):



let http = require('http');

let fs = require('fs');



http.createServer(function (req, res) {

  let size;

  size = fs.statSync("./some/file").size;

  res.setHeader("Content-Type","application/octet-stream");

  res.setHeader("Content-Length", `${size}`);

  res.setHeader("Content-Disposition", "attachment; filename='some.filename'");

  res.flushHeaders();

  

  let seek = 0;

  let buf;

  let bs = 4096;

  let fd;

  fd = fs.openSync("./some/file", "r");

  while (seek < size) {

    buf = Buffer.alloc(bs);

    fs.readSync(fd,buf,null,bs,seek);

    res.write(buf);

    seek = seek + bs

  }

  res.end();

}).listen(8080);

本地使用效果很好。但它在反向代理后面不起作用。浏览器显示错误,在

curl
中我看到:

HTTP/2 stream 1 was not closed cleanly: PROTOCOL_ERROR (err 1)

我使用 nginx 作为反向代理,并且它被配置为在与上游通信时仅使用 http1.1。 如果我这样实现就没有问题:

...
res.end(fs.readFileSync("./some/file"));
...

但是对于几百GB那么大的文件显然是不可能的。 这里不存在XY问题。我知道有一些用于提供文件的工具。我知道nginx可以做到这一点。 但我有兴趣修复我的实现。 由于它只有在反向代理后面时才无法工作,我认为它在某种程度上不符合 HTTP 协议。但我自己却无法弄清楚。 谢谢!

我希望文件传输能够直接和在 Nginx 后面正常工作。

node.js file http nginx nginx-reverse-proxy
1个回答
0
投票

这里的问题很明显,但我花了一些时间才意识到。
身体长度与标题所宣传的不符

Content-Length
标题

当我们

read
进入字节缓冲区时,显然缓冲区仍保持字节长,无论我们读取的数据大小如何。上面的解决方案已经很糟糕了,因为任何文件都会对齐(填充)到 的倍数,但它的致命问题是 不正确的
Content-Length
。因为,考虑到任何文件都被填充为 的倍数,将所讨论的标头的值设置为 文件的实际大小 仅仅意味着设置错误(直到它实际上是 的倍数,这在实践中很少发生) ).

一些 HTTP 实现至少具有最低程度的兼容性,以应对轻微违反 HTTP 标准的情况。但是发送比

Content-Length
中设置的更多/更少的字节就太多了。当直接使用浏览器时,某些浏览器无论如何都会尝试显示响应,尽管长度无效(甚至更糟糕的情况)。但是当使用 Nginx 或其他反向代理时,此类响应导致错误是绝对正确的行为。

© www.soinside.com 2019 - 2024. All rights reserved.