node.js axios下载文件并写入File

时间:2019-03-27 10:17:16

标签: javascript node.js axios

我想使用axios下载pdf文件并使用fs.writeFile保存在磁盘(服务器端)上,我已经尝试过:

axios.get('https://xxx/my.pdf', {responseType: 'blob'}).then(response => {
    fs.writeFile('/temp/my.pdf', response.data, (err) => {
        if (err) throw err;
        console.log('The file has been saved!');
    });
});

文件已保存,但内容已损坏...

如何正确保存文件?

8 个答案:

答案 0 :(得分:38)

实际上,我认为以前接受的答案存在一些缺陷,因为它不能正确处理写流,因此,如果在Axios给您响应后调用“ then()”,您最终将拥有部分下载的文件

当下载稍大的文件时,这是一个更合适的解决方案:

export async function downloadFile(fileUrl: string, outputLocationPath: string) {
  const writer = createWriteStream(outputLocationPath);

  return Axios({
    method: 'get',
    url: fileUrl,
    responseType: 'stream',
  }).then(response => {

    //ensure that the user can call `then()` only when the file has
    //been downloaded entirely.

    return new Promise((resolve, reject) => {
      response.data.pipe(writer);
      let error = null;
      writer.on('error', err => {
        error = err;
        writer.close();
        reject(err);
      });
      writer.on('close', () => {
        if (!error) {
          resolve(true);
        }
        //no need to call the reject here, as it will have been called in the
        //'error' stream;
      });
    });
  });
}

这样,您可以调用downloadFile(),对返回的承诺调用then(),并确保下载的文件已完成处理。

答案 1 :(得分:2)

您可以简单地使用response.data.pipefs.createWriteStream将响应发送到文件中

axios({
    method: "get",
    url: "https://xxx/my.pdf",
    responseType: "stream"
}).then(function (response) {
    response.data.pipe(fs.createWriteStream("/temp/my.pdf"));
});

答案 2 :(得分:2)

// This works perfectly well! 
const axios = require('axios'); 

axios.get('http://www.sclance.com/pngs/png-file-download/png_file_download_1057991.png', {responseType: "stream"} )  
.then(response => {  
// Saving file to working directory  
    response.data.pipe(fs.createWriteStream("todays_picture.png"));  
})  
    .catch(error => {  
    console.log(error);  
});  

答案 3 :(得分:1)

if

对我来说很好

答案 4 :(得分:1)

文件损坏的问题是由于 节点流中的反压 。您可能会发现此链接对于阅读以下内容很有帮助:https://nodejs.org/es/docs/guides/backpressuring-in-streams/

我不是真的喜欢在JS代码中使用Promise基本声明性对象,因为我认为这会污染实际的核心逻辑并使代码难以阅读。最重要的是,您必须提供事件处理程序和侦听器以确保代码完成。

下面给出了与被接受的答案所建议的相同逻辑的更简洁的方法。它使用 流管道 的概念。

npm uninstall nyc
npm i --save-dev nyc

我希望您觉得这有用。

答案 5 :(得分:0)

这是我在节点js上运行的示例代码 出现同步错误

应为 writeFile 而不是 WriteFile

const axios = require('axios');
const fs = require('fs');
axios.get('http://www.africau.edu/images/default/sample.pdf', {responseType: 'blob'}).then(response => {
  fs.writeFile('./my.pdf', response.data, (err) => {
        if (err) throw err;
        console.log('The file has been saved!');
    });
});

文件保存后,在文本编辑器中看起来像,但是文件已正确保存

%PDF-1.3
%����

1 0 obj
<<
/Type /Catalog
/Outlines 2 0 R
/Pages 3 0 R
>>
endobj

2 0 obj
<<
/Type /Outlines
/Count 0
>>
endobj

3 0 obj
<<
/Type /Pages
/Count 2
/Kids [ 4 0 R 6 0 R ] 
>>
endobj

答案 6 :(得分:0)

node fileSystem writeFile默认将数据编码为UTF8。在您的情况下可能是个问题。

尝试将编码设置为null,然后跳过对接收​​到的数据进行编码的操作:

fs.writeFile('/temp/my.pdf', response.data, {encoding: 'null'}, (err) => {...}

如果仅声明编码而没有其他选项,则还可以将编码作为字符串(而不是options对象)进行十进制化。字符串将作为编码值处理。这样:

fs.writeFile('/temp/my.pdf', response.data, 'null', (err) => {...}

更多信息,请参见fileSystem API write_file

答案 7 :(得分:0)

我已经尝试过,并且确信使用response.data.pipefs.createWriteStream可以正常工作。


此外,我想添加我的情况和解决方案

情况:

  • 使用koa开发node.js服务器
  • 使用axios通过网址获取pdf
  • 使用pdf-parse解析pdf
  • 提取pdf的一些信息并将其作为json返回给浏览器

解决方案:

const Koa = require('koa');
const app = new Koa();
const axios = require('axios')
const fs = require("fs")
const pdf = require('pdf-parse');
const utils = require('./utils')

app.listen(process.env.PORT || 3000)

app.use(async (ctx, next) => {
      let url = 'https://path/name.pdf'
      let resp = await axios({
          url: encodeURI(url),
          responseType: 'arraybuffer'
        })

        let data = await pdf(resp.data)

        ctx.body = {
            phone: utils.getPhone(data.text),
            email: utils.getEmail(data.text),
        }
})

在此解决方案中,不需要写入文件和读取文件,效率更高。