如何使用axios下载文件

时间:2017-01-30 14:47:04

标签: reactjs axios

我正在使用axios来获取基本的http请求,例如get和post,它运行良好。现在我需要能够下载excel文件。这可能与axios一起使用。如果是这样,有人有一些示例代码吗?如果不是我还能在反应应用程序中使用什么来做同样的事情呢?

14 个答案:

答案 0 :(得分:39)

当响应带有可下载文件时,响应头将类似于

Content-Disposition: "attachment;filename=report.xls"
Content-Type: "application/octet-stream" // or Content-type: "application/vnd.ms-excel"

您可以做的是创建一个单独的组件,其中包含隐藏的iframe。

  import * as React from 'react';

  var MyIframe = React.createClass({

     render: function() {
         return (
           <div style={{display: 'none'}}>
               <iframe src={this.props.iframeSrc} />
           </div>
         );
     }
  });

现在,您可以将可下载文件的url作为prop传递给此组件,因此当此组件将接收prop时,它将重新呈现并将下载文件。

修改:您还可以使用js-file-download模块。 Link to Github repo

const FileDownload = require('js-file-download');

Axios.get(`http://localhost/downloadFile`)
   .then((response) => {
        FileDownload(response.data, 'report.csv');
   });

希望这会有所帮助:)

答案 1 :(得分:28)

下载文件(使用Axios和安全性)

当您想使用Axios和某些安全手段下载文件时,这实际上更加复杂。为了防止其他人花费太多时间来解决这个问题,让我带你们了解一下。

你需要做三件事:

1. Configure your server to permit the browser to see required HTTP headers
2. Implement the server-side service, and making it advertise the correct file type for the downloaded file.
3. Implementing an Axios handler to trigger a FileDownload dialog within the browser

这些步骤大多是可行的 - 但是由于浏览器与CORS的关系而变得非常复杂。一步一步:

1。配置(HTTP)服务器

在使用传输安全性时,在浏览器中执行的JavaScript可以[通过设计]仅访问HTTP服务器实际发送的6个HTTP头。如果我们希望服务器为下载建议一个文件名,我们必须通知浏览器,“JavaScript”被授予了访问其他标题的权限,这些标题将被传输。

我们假设 - 为了讨论 - 我们希望服务器在名为 X-Suggested-Filename 的HTTP标头中传输建议的文件名。 HTTP服务器告诉浏览器确定将此收到的自定义标头公开给具有以下标题的JavaScript / Axios:

Access-Control-Expose-Headers: X-Suggested-Filename

配置HTTP服务器以设置此标头的确切方法因产品而异。

  

有关这些标准标题的完整说明和详细说明,请参阅https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers

2。实现服务器端服务

您的服务器端服务实现现在必须执行以下两项操作:

1. Create the (binary) document and assign correct ContentType to the response
2. Assign the custom header (X-Suggested-Filename) containing the suggested file name for the client

这取决于您选择的技术堆栈,以不同方式完成。我将使用JavaEE 7标准绘制一个示例,该标准应该发出Excel报告:

@GET
@Path("/report/excel")
@Produces("application/vnd.ms-excel")
public Response getAllergyAndPreferencesReport() {

    // Create the document which should be downloaded
    final byte[] theDocumentData = .... 

    // Define a suggested filename
    final String filename = ... 

    // Create the JAXRS response
    // Don't forget to include the filename in 2 HTTP headers: 
    //
    // a) The standard 'Content-Disposition' one, and
    // b) The custom 'X-Suggested-Filename'  
    //
    final Response.ResponseBuilder builder = Response.ok(
            theDocumentData, "application/vnd.ms-excel")
            .header("X-Suggested-Filename", fileName);
    builder.header("Content-Disposition", "attachment; filename=" + fileName);

    // All Done.
    return builder.build();
}

该服务现在会发出二进制文档(在本例中为Excel报告),设置正确的内容类型 - 还会发送一个自定义HTTP标头,其中包含保存文档时使用的建议文件名。

3。为Received文档实现Axios处理程序

这里有一些陷阱,所以让我们确保正确配置所有细节:

  1. 服务响应@GET(即HTTP GET),因此axios调用必须是'axios.get(...)'。
  2. 文档以字节流的形式传输,因此您必须告知axios将响应视为HTML5 Blob。 (即。 responseType:'blob')。
  3. 在这种情况下,文件保护程序JavaScript库用于弹出浏览器对话框。但是,你可以选择另一个。
  4. 骨架Axios实现将是:

     // Fetch the dynamically generated excel document from the server.
     axios.get(resource, {responseType: 'blob'}).then((response) => {
    
        // Log somewhat to show that the browser actually exposes the custom HTTP header
        const fileNameHeader = "x-suggested-filename";
        const suggestedFileName = response.headers[fileNameHeader];'
        const effectiveFileName = (suggestedFileName === undefined
                    ? "allergierOchPreferenser.xls"
                    : suggestedFileName);
        console.log("Received header [" + fileNameHeader + "]: " + suggestedFileName
                    + ", effective fileName: " + effectiveFileName);
    
        // Let the user save the file.
        FileSaver.saveAs(response.data, effectiveFileName);
    
        }).catch((response) => {
            console.error("Could not Download the Excel report from the backend.", response);
        });
    

答案 2 :(得分:11)

更通用的解决方案

axios({
  url: 'http://api.dev/file-download', //your url
  method: 'GET',
  responseType: 'blob', // important
}).then((response) => {
   const url = window.URL.createObjectURL(new Blob([response.data]));
   const link = document.createElement('a');
   link.href = url;
   link.setAttribute('download', 'file.pdf'); //or any other extension
   document.body.appendChild(link);
   link.click();
});

https://gist.github.com/javilobo8/097c30a233786be52070986d8cdb1743上查看怪癖

满分:https://gist.github.com/javilobo8

答案 3 :(得分:1)

这对我有用。我在 reactJS 中实现了这个解决方案

const requestOptions = {`enter code here`
method: 'GET',
headers: { 'Content-Type': 'application/json' }
};

fetch(`${url}`, requestOptions)
.then((res) => {
    return res.blob();
})
.then((blob) => {
    const href = window.URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = href;
    link.setAttribute('download', 'config.json'); //or any other extension
    document.body.appendChild(link);
    link.click();
})
.catch((err) => {
    return Promise.reject({ Error: 'Something Went Wrong', err });
})

答案 4 :(得分:0)

诀窍是在render()中创建一个不可见的锚标记,并添加一个React ref,以便在收到axios响应后触发点击:

class Example extends Component {
    state = {
        ref: React.createRef()
    }

    exportCSV = () => {
        axios.get(
            '/app/export'
        ).then(response => {
            let blob = new Blob([response.data], {type: 'application/octet-stream'})
            let ref = this.state.ref
            ref.current.href = URL.createObjectURL(blob)
            ref.current.download = 'data.csv'
            ref.current.click()
        })
    }

    render(){
        return(
            <div>
                <a style={{display: 'none'}} href='empty' ref={this.state.ref}>ref</a>
                <button onClick={this.exportCSV}>Export CSV</button>
            </div>
        )
    }
}

以下是文档:https://reactjs.org/docs/refs-and-the-dom.html。您可以在这里找到类似的想法:https://thewebtier.com/snippets/download-files-with-axios/

答案 5 :(得分:0)

        axios.get(
            '/app/export'
        ).then(response => {    
            const url = window.URL.createObjectURL(new Blob([response]));
            const link = document.createElement('a');
            link.href = url;
            const fileName = `${+ new Date()}.csv`// whatever your file name .
            link.setAttribute('download', fileName);
            document.body.appendChild(link);
            link.click();
            link.remove();// you need to remove that elelment which is created before.
})

答案 6 :(得分:0)

使用IE和其他浏览器的Axios.post解决方案

在这里找到了一些令人难以置信的解决方案。但是他们经常不考虑IE浏览器的问题。也许可以节省一些时间。

 axios.post("/yourUrl"
                , data,
                {responseType: 'blob'}
            ).then(function (response) {
                    let fileName = response.headers["content-disposition"].split("filename=")[1];
                    if (window.navigator && window.navigator.msSaveOrOpenBlob) { // IE variant
                        window.navigator.msSaveOrOpenBlob(new Blob([response.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}),
                            fileName);
                    } else {
                        const url = window.URL.createObjectURL(new Blob([response.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}));
                        const link = document.createElement('a');
                        link.href = url;
                        link.setAttribute('download', response.headers["content-disposition"].split("filename=")[1]);
                        document.body.appendChild(link);
                        link.click();
                    }
                }
            );
上面的

例子适用于excel文件,但是几乎可以将其应用于任何格式。

在服务器上,我这样做是为了发送excel

response.contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"

response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=exceptions.xlsx")

答案 7 :(得分:0)

这是触发用户下载的非常简单的javascript代码:

window.open("<insert URL here>")

您不需要/不需要axios进行此操作;只是让浏览器来做就可以了。


关于是否可能 ... not with the in-built file downloading mechanism, no

答案 8 :(得分:0)

  

使用axios进行API调用的函数:

  function getFileToDownload (apiUrl) {
     return axios.get(apiUrl, {
       responseType: 'arraybuffer',
       headers: {
         'Content-Type': 'application/json'
       }
     })
  }
  

调用该函数,然后下载获得的excel文件:

getFileToDownload('putApiUrlHere')
  .then (response => {
      const type = response.headers['content-type']
      const blob = new Blob([response.data], { type: type, encoding: 'UTF-8' })
      const link = document.createElement('a')
      link.href = window.URL.createObjectURL(blob)
      link.download = 'file.xlsx'
      link.click()
  })

答案 9 :(得分:0)

为 Received 文档实现一个 Axios 处理程序,数据格式为 octect-stream, 数据可能看起来很奇怪 PK something JbxfFGvddvbdfbVVH34365436fdkln 作为其八位字节流格式,您最终可能会使用此数据创建文件可能已损坏,{responseType: 'blob'} 会将数据转换为可读格式,

axios.get("URL", {responseType: 'blob'})
     .then((r) => {
         let fileName =  r.headers['content-disposition'].split('filename=')[1];
         let blob = new Blob([r.data]);
         window.saveAs(blob, fileName);             
      }).catch(err => {
        console.log(err);
      });

您可能尝试过这样失败的解决方案, window.saveAs(blob, 'file.zip') 会尝试将文件另存为 zip,但不会工作,

const downloadFile = (fileData) => {
    axios.get(baseUrl+"/file/download/"+fileData.id)
        .then((response) => {
            console.log(response.data);
            const blob = new Blob([response.data], {type: response.headers['content-type'], encoding:'UTF-8'});
            const link = document.createElement('a');
            link.href = window.URL.createObjectURL(blob);
            link.download = 'file.zip';
            link.click();
        })
        .catch((err) => console.log(err))
}
const downloadFile = (fileData) => {
axios.get(baseUrl+"/file/download/"+fileData.id)
    .then((response) => {
        console.log(response);
        //const binaryString = window.atob(response.data)
        //const bytes = new Uint8Array(response.data)
        //const arrBuff = bytes.map((byte, i) => response.data.charCodeAt(i));
        //var base64 = btoa(String.fromCharCode.apply(null, new Uint8Array(response.data)));
        const blob = new Blob([response.data], {type:"application/octet-stream"});
        window.saveAs(blob, 'file.zip')
        // const link = document.createElement('a');
        // link.href = window.URL.createObjectURL(blob);
        // link.download = 'file.zip';
        // link.click();
    })
    .catch((err) => console.log(err))
}
function base64ToArrayBuffer(base64) {
    var binaryString = window.atob(base64);
    var binaryLen = binaryString.length;
    var bytes = new Uint8Array(binaryLen);
    for (var i = 0; i < binaryLen; i++) {
        var ascii = binaryString.charCodeAt(i);
        bytes[i] = ascii;
    };

    return bytes;
}

另一个简短的解决方案是,

window.open("URL")

会继续不必要地打开新标签页,用户可能需要制作 allow popups 才能使用此代码,如果用户想同时下载多个文件怎么办,请先使用解决方案,否则也可以尝试其他解决方案

答案 10 :(得分:0)

您需要将 File({file_to_download}, "application/vnd.ms-excel") 从后端返回到前端,并且在您的 js 文件中您需要更新下面编写的代码:

function exportToExcel() {
        
        axios.post({path to call your controller}, null,
            {
                headers:
                {
                    'Content-Disposition': "attachment; filename=XYZ.xlsx",
                    'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
                },
                responseType: 'arraybuffer',
            }
        ).then((r) => {
            const path= window.URL.createObjectURL(new Blob([r.data]));
            const link = document.createElement('a');
            link.href = path;
            link.setAttribute('download', 'XYZ.xlsx');
            document.body.appendChild(link);
            link.click();
        }).catch((error) => console.log(error));
    }

答案 11 :(得分:0)

此功能将帮助您下载准备好的 xlsx、csv 等文件下载。我只是从后端发送了一个准备好的 xlsx 静态文件,然后它做出反应。

const downloadFabricFormat = async () => {
    try{
      await axios({
        url: '/api/fabric/fabric_excel_format/',
        method: 'GET',
        responseType: 'blob',
      }).then((response) => {
         const url = window.URL.createObjectURL(new Blob([response.data]));
         const link = document.createElement('a');
         link.href = url;
         link.setAttribute('download', 'Fabric Excel Format.xlsx');
         document.body.appendChild(link);
         link.click();
      });
    } catch(error){
      console.log(error)
    }
  };

答案 12 :(得分:-1)

对于axios POST请求,该请求应如下所示: 这里的关键是echo "Please Name Folder" SET /p template= setlocal enabledelayedexpansion md C:\Users\Obi\Desktop\%template%\Pictures md C:\Users\Obi\Desktop\%template%\Videos :choice SET /p c=Does the Folder Contain Videos[Y/N/]? if /I "%c%" EQU "Y" goto :Videos if /I "%c%" EQU "N" goto :Pictures goto :choice :Videos echo "Please Add Folder Name" SET /p SubFolder= md C:\Users\Obi\Desktop\%template%\Videos\%SubFolder% start C:\Users\Obi\Desktop\%template% pause exit :Pictures echo "Please Add Folder Name" SET /p SubFolder= md C:\Users\Obi\Desktop\%template%\Pictures\%SubFolder% start C:\Users\Obi\Desktop\%template% pause exit responseType字段必须在Post的第3个参数中。第二个参数是应用程序参数。

header

答案 13 :(得分:-3)

我的回答是总黑客 - 我刚创建了一个看起来像按钮的链接,并将URL添加到该按钮。

<a class="el-button"
  style="color: white; background-color: #58B7FF;"
  :href="<YOUR URL ENDPOINT HERE>"
  :download="<FILE NAME NERE>">
<i class="fa fa-file-excel-o"></i>&nbsp;Excel
</a>

我正在使用优秀的VueJs因此奇怪的anotations,但是,这个解决方案是框架无关的。这个想法适用于任何基于HTML的设计。

相关问题