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

时间:2015-05-26 12:02:22

标签: javascript node.js express base64 utf-16

提前致谢。

短:

由于请求中的Accept标头,Express JS 4.0会更改输出数据。 有没有办法让我覆盖这种行为,只需编写相同的数据,无论请求标头如何。

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

有没有办法可以忽略,删除,覆盖这些标题。

长(可能是tl; dr):

我正在尝试从Node / ExpressJS应用程序提供二进制数据。 我正在存储一个压缩的日志文件(纯文本/文本),它已被gzip压缩,base64编码并发送到我的服务器应用程序,在那里它使用mongoose存储在mongo数据库中。我知道这可能不是最佳,但目前是一个必要的邪恶。这很好。

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

在将数据作为json帖子的一部分与其他数据一起发送之前,用于压缩和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 endianess。

最终发现这一切都不是问题,我原以为NodeJS一直在向浏览器输出错误的数据,这是正确的,但它不是"总是"输出错误的数据。

我有一个突破,当我向端点发出curl请求,并且数据按预期传出(与源匹配)时,我添加了随浏览器请求发送的请求标头,然后返回错误的数据。

实际日志文件:

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                   .;_._....

1 个答案:

答案 0 :(得分:1)

res.end(node.log, 'base64');

而不是

res.send(log);

其中node.log是原始base64编码的String,而log是已解码该字符串的Buffer。

请记住我使用的是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'标头不存在时,此行为不同,在这种情况下调用了不同的end(chunk, encoding)函数,而不是使用res.inject而不是修改缓冲区数据。

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