简体   繁体   English

从 http 下载 PDF 响应 Axios

[英]Download PDF from http response with Axios

I am working on a Vue application with a Laravel back-end API. After clicking on a link I would like to do a call to the server to download a certain file (most of the time a PDF file).我正在开发一个后端为 Laravel API 的 Vue 应用程序。单击链接后,我想调用服务器以下载某个文件(大部分时间为 PDF 文件)。 When I do a get request with axios I get a PDF in return, in the body of the response.当我使用axios发出get请求时,我在响应正文中得到 PDF 作为回报。 I would like to download that file directly.我想直接下载那个文件。

To give you a better view of how the response is looking like:为了让您更好地了解响应的样子:

在此处输入图像描述 (note: I know a real text response is better than an image but I don't see any way to return that because of the length of the actual PDF content..) (注意:我知道真实的文本响应比图像更好,但由于实际 PDF 内容的长度,我看不到任何返回方式。)

Is there any way of downloading that file with JavaScript or something?有什么办法可以用 JavaScript 之类的方式下载那个文件吗? It has to be specific a direct download without clicking on the button again.它必须是特定的直接下载而无需再次单击按钮。

Code代码

// This method gets called when clicking on a link
downloadFile(id) {
    const specificationId = this.$route.params.specificationId;

    axios
        .get(`${this.$API_URL}/api/v1/suppliersmanagement/product-specifications/${specificationId}/fileupload/${id}/download`, {
            headers: this.headers,
        })
        .then(response => {
            console.log(response);
            // Direct download the file here..
        })
        .catch(error => console.log(error));
},

As @Sandip Nirmal suggested I've used downloadjs and that worked out pretty good!正如@Sandip Nirmal 建议的那样,我使用了downloadjs ,效果非常好! Had to make a few adjustments to my code but in the end it worked out.不得不对我的代码进行一些调整,但最终它成功了。

My new code我的新代码

// npm i downloadjs
import download from 'downloadjs'

// method
downloadFile(file) {
    const specificationId = this.$route.params.specificationId;

    axios
        .get(`${this.$API_URL}/api/v1/suppliersmanagement/product-specifications/${specificationId}/fileupload/${file.id}/download`, {
            headers: this.headers,
            responseType: 'blob', // had to add this one here
        })
        .then(response => {
           const content = response.headers['content-type'];
           download(response.data, file.file_name, content)
        })
        .catch(error => console.log(error));
},

You should use 'responseType' option.您应该使用“responseType”选项。 For example:例如:

axios.get(
  url, 
  {responseType: 'blob'} // !!!
).then((response) => {
  window.open(URL.createObjectURL(response.data));
})

You have 2 options for this.为此,您有 2 个选项。 If you want to do it from server and if you are using Node.js as a backend.如果您想从服务器执行此操作,并且您使用 Node.js 作为后端。 You can do it easily using res.download method of express.您可以使用 express 的res.download方法轻松完成。 You can follow this answer for that Download a file from NodeJS Server using Express .您可以按照这个答案使用 Express 从 NodeJS 服务器下载文件

But if you want to handle it from client then there are few options since you can't use axios, XHR, fetch to download file directly.但是,如果您想从客户端处理它,那么选择很少,因为您不能使用 axios、XHR、fetch 直接下载文件。 You can either use download.js or write your own code in following way.您可以使用download.js或通过以下方式编写自己的代码。

return axios({
    url: '/download', // download url
    method: 'get',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
      mode: 'no-cors'
    }
  })
    .then(response => response.blob())
    .then(blob => {
      var url = window.URL.createObjectURL(blob)
      var a = document.createElement('a')
      a.href = url
      a.download = fileName
      a.click()
      a.remove()
      setTimeout(() => window.URL.revokeObjectURL(url), 100)
    })

Since response returned from server is in json format you need to convert it into ObjectURL and set it to anchor tag.由于从服务器返回的响应是json格式,您需要将其转换为ObjectURL并将其设置为锚标记。

If you sneak inside download.js code you will find same implementation.如果你潜入download.js代码,你会发现相同的实现。

You can do it like this你可以这样做

download(filename) {
  fetch(url , { headers })
  .then(response => response.blob())
  .then(blob => URL.createObjectURL(blob))
  .then(uril => {
    var link = document.createElement("a");
    link.href = uril;
    link.download = filename + ".csv";
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  });
}

here I want to download a CSV file, So I add .csv to the filename.在这里我想下载一个 CSV 文件,所以我将 .csv 添加到文件名中。

2022 answer: using node.js, fs.promises and async/await 2022 答案:使用 node.js、fs.promises 和 async/await

The key is using responseType: 'stream' per the Axios docs .关键是使用responseType: 'stream' per the Axios docs

import axios from 'axios';
import { writeFile } from 'fs/promises';

const downloadFile = async () => {
  const response = await axios.get('https://someurl', {
    params: {
      // ...
    },
    // See https://axios-http.com/docs/api_intro
    responseType: 'stream',
  });
  const pdfContents = response.data;
  await writeFile('file.pdf', pdfContents);
};

const downloadPDF = (id, fileName) => {
    axios({
        method: 'get',
        url: `https://api.example.com/pdf/invoice/${id}`,
        headers: {
            'Authorization': 'Bearer ' + localStorage.getItem('token'),
            'Content-Type': 'application/json'
        },
        responseType: 'blob'
    }).then(function (response) {
        const a = document.createElement('a');
        a.href = window.URL.createObjectURL(response.data);
        a.download = `${fileName}.pdf`;
        document.body.appendChild(a);
        a.click();
        a.remove();
    });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM