Express JS 4.0,提供二进制数据,请求 Accept header 更改输出

Express JS 4.0, serve binary data, request Accept header changes output

提前致谢。

短:

Express JS 4.0 由于请求中的 Accept headers 改变了输出数据。 有没有办法让我覆盖这种行为,并且无论请求如何都只写相同的数据 headers.

当存在 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 时,输出发生变化。

有什么方法可以忽略、删除、覆盖这些 headers。

长(可能 tl;dr):

我正在尝试从 Node/ExpressJS 应用程序提供二进制数据。 我正在存储一个压缩的日志文件 (plain/text),该文件经过 gzip 压缩、base64 编码并发送到我的服务器应用程序,在那里使用 mongoose 将其存储在 mongo 数据库中。我知道这可能不是最优的,但目前是一个必要的邪恶。这工作正常。

$(gzip --stdout /var/log/cloud-init-script.log | base64 --wrap=0)

在将数据作为 json post.

的一部分与其他数据一起发送之前,正用于压缩和 base64 数据

当我尝试检索、解码 base64 编码的字符串并将其作为二进制 gzip 文件发送到浏览器时出现问题。

// node, referring to the machine the log came from
var log = new Buffer(node.log, 'base64');

res.setHeader('Content-Disposition', 'attachment; filename=' + node.name + "-log.gz");
res.setHeader('Content-Type', 'application/x-gzip');
res.setHeader('Content-Length', log.length);

console.log(log.toString('hex'));
// res.end(log, 'binary'); I tried this hoping I could by pass, some content-negotiation
res.send(log);

我在使用 res.send 使用 ExpressJS 3.0 时可以正常工作。 但是当我将下载的数据更新到 ExpressJS 4.0 时,无法正确提取。被拉下的数据似乎以某种方式损坏了。

我开始尝试通过使用 xxdod 比较下载文件和十六进制输出中的源文件来修复此问题,发现下载文件与源文件不同。在将 NodeJS 缓冲区发送到客户端进行控制台之前,我还转储了它的十六进制,这与源匹配。

我已经为这个问题苦苦思索了将近一天,并且怀疑 NodeJS 可能在使用字符编码(UTF-8 v. Buffer v. UTF16 Strings)做一些时髦的事情,OS 字节顺序。

最终发现 none 这个问题,我假设 NodeJS 一直在向浏览器输出错误的数据,这是正确的,但不是 "Always" 输出错误数据。

我有一个突破,当我向端点发出 curl 请求时,数据按预期通过(与源匹配),然后我添加了通过我的浏览器发送的请求 headers请求,并取回损坏的数据。

实际日志文件:

I'm a log file

好的请求:

> User-Agent: curl/7.37.1
> Host: 127.0.0.1:9000
> Accept: */*
> 
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Last-Modified: Tue, 26 May 2015 11:47:46 GMT
< Content-Description: File Transfer
< Content-Disposition: attachment; filename=test-log.gz
< Content-Type: application/x-gzip
< Content-Transfer-Encoding: binary
< Content-Length: 57
< Date: Tue, 26 May 2015 11:47:46 GMT
< Connection: keep-alive

0000000: 1f8b 0808 0256 6455 0003 636c 6f75 642d  .....VdU..cloud-
0000010: 696e 6974 2d73 6372 6970 742e 6c6f 6700  init-script.log.
0000020: f354 cf55 4854 c8c9 4f57 48cb cc49 e502  .T.UHT..OWH..I..
0000030: 003b 5ff5 5f0f 0000 00                   .;_._....

错误请求:

> Host: localhost:9000
> Connection: keep-alive
> Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
> User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.65 Safari/537.36
> Referer: http://localhost:9000/nodes?query=environment%3D5549b6cbdc023b5e26fe6bd4%20type%3Dnat
> Accept-Language: en-US,en;q=0.8
> 
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Last-Modified: Tue, 26 May 2015 11:47:00 GMT
< Content-Description: File Transfer
< Content-Disposition: attachment; filename=test-log.gz
< Content-Type: application/x-gzip
< Content-Transfer-Encoding: binary
< content-length: 57
< Date: Tue, 26 May 2015 11:47:00 GMT
< Connection: keep-alive

0000000: 1ffd 0808 0256 6455 0003 636c 6f75 642d  .....VdU..cloud-
0000010: 696e 6974 2d73 6372 6970 742e 6c6f 6700  init-script.log.
0000020: fd54 fd55 4854 fdfd 4f57 48fd fd49 fd02  .T.UHT..OWH..I..
0000030: 003b 5ffd 5f0f 0000 00                   .;_._....
res.end(node.log, 'base64');

而不是

res.send(log);

其中 node.log 是原始的 base64 编码字符串,log 是解码该字符串的缓冲区。

请注意,我使用的是 Node v0.10.38。

我最终遵循了函数调用链。

// I call
res.send(log);
// ExpressJS calls on http.ServerResponse
this.end(chunk, encoding); // chunk = Buffer, encoding = undefined
// NodeJS http.ServerResponse calls
res.inject(string);

此时 NodeJS 似乎将数据视为字符串,这是缓冲区内容被破坏的地方。

'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' header 不存在时,这种行为是不同的,在这种情况下调用了不同的 end(chunk, encoding) 函数,不使用 res.inject 也没有 mangling缓冲区数据。

我不完全确定内容协商在哪里发生以及在不同 res.end 函数中交换了什么,无论是 NodeJS 还是 ExpressJS,但是能够控制此内容协商会很好以某种简单的方式。