用nodejs下载phar。应该使用哪种编码?

时间:2017-08-18 17:51:26

标签: php node.js phar

我尝试使用node.js中的程序下载phar(PHP Archive)。经过一些测试后,我发现从浏览器和node.js下载的文件不一样。

我尝试了一些事情:
"二进制"编码
" UTF8"编码
这些都不起作用。

有谁知道我应该使用哪种编码来下载phar?
我的代码:



exports.download = function(urlStr, dest, cb) { // urlStr is the url link of the phar, dest is the destination file, and cb is the callback.
var options = {
    headers: {
        "User-Agent": "PSM (Pocketmine Server Manager, https://psm.mcpe.fun) User Requester"
    }
}
var data = "";
var url = new URL(urlStr);
options.hostname = url.hostname;
options.path = url.pathname;
var request = http.get(options, function(response) {
    // check if response is success
    if (response.statusCode == 302 || response.statusCode == 301) {
        exports.download(response.headers["location"], dest, cb);
        return;
    }
    response.on("data", function(chunk) {
        data += chunk.toString("binary");
    })
    response.on('end', function() {
        fs.writeFileSync(dest, data, "binary");
        cb();
    });
}).on('error', function(err) { // Handle errors
    fs.unlink(dest); // Delete the file async. (But we don't check the result)
    if (cb) cb(err.message);
});
};




Phar使用(有效):https://psm.mcpe.fun/download/PSMCore/1.1.phar

1 个答案:

答案 0 :(得分:1)

我注意到原始代码中存在一些问题:

  • 主要问题是二进制数据被隐式转换为UTF-8字符串,保留内容。将数据保存在Buffer格式中,只需使用流将响应传输到磁盘,而不是首先在内存中缓冲整个响应。

  • 在节点中使用异步回调时,按照惯例,您将实际的Error对象作为第一个参数而不是字符串传递。很多时候,这些对象提供的信息要么不包含在消息本身中,要么不能从错误消息中轻易解析(例如堆栈跟踪,libuv错误代码,上下文信息,如http URI,文件路径,主机名等)。

  • 在将响应保存到磁盘之前,未检查200状态代码。您最终可能会将错误的html页面(例如400,404等)保存到磁盘而不是您期望的那样。您还应该检查Content-Type标头是否是您期望的,以进一步确保响应符合您的预期。

修复前两项的示例是:

var res;
function onError(err) {
  if (res) {
    res.resume(); // Ensure response is drained
    res = null;
  }
  if (cb) {
    fs.unlink(dest, function() {});
    cb(err);
    cb = null;
  }
}
http.get(options, function(response) {
  // Check if response is success
  if (response.statusCode === 302 || response.statusCode === 301) {
    exports.download(response.headers["location"], dest, cb);
    res.resume(); // Ensure response is drained
    return;
  }
  res = response;
  var out = fs.createWriteStream(dest);
  out.on('error', onError);
  response.pipe(out).on('close', function() {
    if (cb) {
      cb();
      cb = null;
    }
  });
}).on('error', onError);