Node.js - Browserify:解析 tar 文件时出错
Node.js - Browserify: Error on parsing tar file
我正在尝试通过 HTTP 下载 tar
文件 (non-compressed) 并将其响应传输到 tar-stream 解析器以进行进一步处理。这在终端上执行时非常完美,没有任何错误。对于要在浏览器上使用的相同内容,使用 browserify
生成 bundle.js
文件并包含在 HTML.
中
tar 流包含 3 个文件。此浏览器化代码在浏览器上执行时成功解析了 2 个条目,但对第三个条目引发了以下错误:
Error: Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?
而使用相同的 HTTP 下载和解析代码,tar 文件在终端上完全没有错误地下载和解析。为什么会这样?!
代码片段如下:
. . . .
var req = http.request(url, function(res){
res.pipe(tar.extract())
.on('entry', function(header, stream, callback) {
console.log("File found " + header.name);
stream.on('end', function() {
console.log("<<EOF>>");
callback();
})
stream.resume();
})
.on('finish', function(){
console.log("All files parsed");
})
.on('error', function(error){
console.log(error); //Raises the above mentioned error here
})
});
. . . .
有什么建议吗? Headers?
此处的问题(及其解决方案)隐藏在 http-browserify 文档中。首先,你需要了解一些关于 browserify 的事情:
- 浏览器环境与node.js环境不一样
- Browserify 尽最大努力提供 node.js 当您正在浏览的代码需要它们时浏览器中不存在的 API
- 替换行为与 node.js 中的行为不完全相同,并且在浏览器中受到警告
考虑到这一点,您至少使用了三个具有 browserify reimplementations/shims 的特定于节点的 API:网络连接、缓冲区和流。浏览器中的网络连接必然会被 XHR 调用所取代,XHR 调用有自己的语义,围绕着二进制数据,这些数据在 Node [Node has Buffers] 中不存在。如果您查看 here,您会注意到一个名为 responseType
的选项;这设置了 XHR 调用的响应类型,必须这样做才能确保您返回二进制数据而不是字符串数据。子栈建议使用ArrayBuffer
;由于这必须在 http.request
的 options
对象上设置,因此您需要使用长格式请求格式而不是字符串-url 格式:
http.request({
method: 'GET',
hostname: 'www.site.com',
path: '/path/to/request',
responseType: 'arraybuffer' // note: lowercase
}, function (res) {
// ...
});
参见 the xhr spec for valid values for responseType. http-browserify passes it along as-is。在 Node 中,这个键将被简单地忽略。
当您将响应类型设置为 'arraybuffer' 时,http-browserify 将在构造函数中 emit chunks as Uint8Array
. Once you're getting a Uint8Array
back from http.request
, another problem presents itself: the Stream
API only accepts string
and Buffer
for input, so when you pipe the response to the tar extractor stream, you'll receive TypeError: Invalid non-string/buffer chunk
. This seems to me to be an oversight in stream-browserify
, which should accept Uint8Array values to go along nicely with the other parts of the browserified Node API. You can fairly simply work around it yourself, though. The Buffer shim in the browser accepts a typed array,因此您可以自己通过管道传输数据,手动将每个块转换为 Buffer
:
http.request(opts, function (res) {
var tarExtractor = tar.extract();
res.on('data', function (chunk) {
tarExtractor.write(new Buffer(chunk));
});
res.on('end', function () {
tarExtractor.end();
});
res.on('error', function (err) {
// do something with your error
// and clean up the tarExtractor instance if necessary
});
});
那么您的代码应该如下所示:
var req = http.request({
method: 'GET',
// Add your request hostname, path, etc. here
responseType: 'arraybuffer'
}, function(res){
var tarExtractor = tar.extract();
res.on('data', function (chunk) {
tarExtractor.write(new Buffer(chunk));
});
res.on('end', tarExtractor.end.bind(tarExtractor));
res.on('error', function (error) {
console.log(error);
});
tarExtractor.on('entry', function(header, stream, callback) {
console.log("File found " + header.name);
stream.on('end', function() {
console.log("<<EOF>>");
callback();
})
stream.resume(); // This won't be necessary once you do something with the data
})
.on('finish', function(){
console.log("All files parsed");
});
});
我正在尝试通过 HTTP 下载 tar
文件 (non-compressed) 并将其响应传输到 tar-stream 解析器以进行进一步处理。这在终端上执行时非常完美,没有任何错误。对于要在浏览器上使用的相同内容,使用 browserify
生成 bundle.js
文件并包含在 HTML.
tar 流包含 3 个文件。此浏览器化代码在浏览器上执行时成功解析了 2 个条目,但对第三个条目引发了以下错误:
Error: Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?
而使用相同的 HTTP 下载和解析代码,tar 文件在终端上完全没有错误地下载和解析。为什么会这样?!
代码片段如下:
. . . .
var req = http.request(url, function(res){
res.pipe(tar.extract())
.on('entry', function(header, stream, callback) {
console.log("File found " + header.name);
stream.on('end', function() {
console.log("<<EOF>>");
callback();
})
stream.resume();
})
.on('finish', function(){
console.log("All files parsed");
})
.on('error', function(error){
console.log(error); //Raises the above mentioned error here
})
});
. . . .
有什么建议吗? Headers?
此处的问题(及其解决方案)隐藏在 http-browserify 文档中。首先,你需要了解一些关于 browserify 的事情:
- 浏览器环境与node.js环境不一样
- Browserify 尽最大努力提供 node.js 当您正在浏览的代码需要它们时浏览器中不存在的 API
- 替换行为与 node.js 中的行为不完全相同,并且在浏览器中受到警告
考虑到这一点,您至少使用了三个具有 browserify reimplementations/shims 的特定于节点的 API:网络连接、缓冲区和流。浏览器中的网络连接必然会被 XHR 调用所取代,XHR 调用有自己的语义,围绕着二进制数据,这些数据在 Node [Node has Buffers] 中不存在。如果您查看 here,您会注意到一个名为 responseType
的选项;这设置了 XHR 调用的响应类型,必须这样做才能确保您返回二进制数据而不是字符串数据。子栈建议使用ArrayBuffer
;由于这必须在 http.request
的 options
对象上设置,因此您需要使用长格式请求格式而不是字符串-url 格式:
http.request({
method: 'GET',
hostname: 'www.site.com',
path: '/path/to/request',
responseType: 'arraybuffer' // note: lowercase
}, function (res) {
// ...
});
参见 the xhr spec for valid values for responseType. http-browserify passes it along as-is。在 Node 中,这个键将被简单地忽略。
当您将响应类型设置为 'arraybuffer' 时,http-browserify 将在构造函数中 emit chunks as Uint8Array
. Once you're getting a Uint8Array
back from http.request
, another problem presents itself: the Stream
API only accepts string
and Buffer
for input, so when you pipe the response to the tar extractor stream, you'll receive TypeError: Invalid non-string/buffer chunk
. This seems to me to be an oversight in stream-browserify
, which should accept Uint8Array values to go along nicely with the other parts of the browserified Node API. You can fairly simply work around it yourself, though. The Buffer shim in the browser accepts a typed array,因此您可以自己通过管道传输数据,手动将每个块转换为 Buffer
:
http.request(opts, function (res) {
var tarExtractor = tar.extract();
res.on('data', function (chunk) {
tarExtractor.write(new Buffer(chunk));
});
res.on('end', function () {
tarExtractor.end();
});
res.on('error', function (err) {
// do something with your error
// and clean up the tarExtractor instance if necessary
});
});
那么您的代码应该如下所示:
var req = http.request({
method: 'GET',
// Add your request hostname, path, etc. here
responseType: 'arraybuffer'
}, function(res){
var tarExtractor = tar.extract();
res.on('data', function (chunk) {
tarExtractor.write(new Buffer(chunk));
});
res.on('end', tarExtractor.end.bind(tarExtractor));
res.on('error', function (error) {
console.log(error);
});
tarExtractor.on('entry', function(header, stream, callback) {
console.log("File found " + header.name);
stream.on('end', function() {
console.log("<<EOF>>");
callback();
})
stream.resume(); // This won't be necessary once you do something with the data
})
.on('finish', function(){
console.log("All files parsed");
});
});