如何使用axios下载文件

Dav*_*hoi 45 reactjs axios

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

Har*_*dha 54

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

Content-Disposition: "attachment;filename=report.xls"
Content-Type: "application/octet-stream" // or Content-type: "application/vnd.ms-excel"
Run Code Online (Sandbox Code Playgroud)

你可以做的是创建一个单独的组件,它将包含一个隐藏的iframe.

  import * as React from 'react';

  var MyIframe = React.createClass({

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

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

编辑:您也可以使用js-file-download模块.链接到Github回购

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

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

希望这可以帮助 :)

  • 我按照此操作并能够下载该文件。但文件已损坏(不起作用)。但是,如果我使用重定向( window.location.href ),文件将下载并正常工作。有人可以帮我解决这个问题吗?(/sf/ask/3941420591/ Correctly-using-axios) (2认同)

Len*_*lid 36

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

当您想要使用Axios和某些安全手段下载文件时,这实际上更加复杂.为了防止其他人花费太多时间来搞清楚这一点,让我带你走过这个.

你需要做3件事:

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
Run Code Online (Sandbox Code Playgroud)

这些步骤大多是可行的 - 但是浏览器与CORS的关系很复杂.一步一步来:

1.配置(HTTP)服务器

在使用传输安全性时,在浏览器中执行的JavaScript可以[通过设计]仅访问HTTP服务器实际发送的6个HTTP头.如果我们想在服务器建议为下载的文件名,我们必须告知这是"OK"的JavaScript来被授予访问到文件名建议将运送其他头的浏览器.

让我们假设 - 为了讨论 - 我们希望服务器在名为X-Suggested-Filename的HTTP头中传输建议的文件名.HTTP服务器告诉它是浏览器OK揭露这个接收到的自定义标题的JavaScript /爱可信与下面的头:

Access-Control-Expose-Headers: X-Suggested-Filename
Run Code Online (Sandbox Code Playgroud)

配置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
Run Code Online (Sandbox Code Playgroud)

这取决于您选择的技术堆栈,以不同的方式完成.我将使用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();
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

骨架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);
    });
Run Code Online (Sandbox Code Playgroud)

  • 什么是"FileSaver"? (15认同)
  • 这很好,但它错过了一个核心点,即使用 blob 执行 ```axios.get(resource, {responseType: 'blob'}).then((response) =&gt; () =&gt; {})```作为responseType,整个文件都会加载到内存中并*然后*进行处理,即使服务器将数据作为块传输也是如此。这很重要,因为您最终必须实现自己的进度条,因为您无法使用浏览器提供的本机进度条。这是xhr本身的缺点。 (8认同)
  • 它是一个处理下载文件的库,https://github.com/eligrey/FileSaver.js/#filesaverjs (4认同)
  • @KJSudarshan你知道大文件的解决方案是什么吗?我目前遇到这个问题:( (4认同)
  • 这可行,但是建议使用“ content-disposition”标头而不是“ x-suggested-filename”。 (2认同)

Vin*_*ney 35

更通用的解决方案

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();
});
Run Code Online (Sandbox Code Playgroud)

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

完整学分:https://gist.github.com/javilobo8

  • 谢谢你。想知道为什么文件内容没有正确显示。原来我缺少 `responseType: 'blob'` (5认同)
  • @Vinay 这个解决方案有内存开销。不需要 ```document.body.appendChild(link)```。还可以在 ```link.click()``` 之后使用 ```window.URL.revokeObjectURL(url)``` (4认同)
  • 谢谢您的解决方案。谨为其他人提供一些注意事项:尽管这在许多用例中都可行,但对于大文件,您将无法看到下载进度。并且它将在浏览器中占用额外的内存。正如在其他解决方案中提到的一样,但没有明确指出,一般的方法是使用标头“ Content-Disposition:Attachment;”。因此浏览器会将其视为本机下载(上述下载进度+直接下载到磁盘)。 (3认同)
  • 在服务器端,即使我设置了 Content-Desposition 标头,它似乎也不允许下载进度。 (2认同)
  • 我们需要“document.body.appendChild(link);”行吗?没有这个解决方案对我有用(Chrome) (2认同)

Ale*_*lex 24

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();
                    }
                }
            );
Run Code Online (Sandbox Code Playgroud)

上面的示例适用于 excel 文件,但只需稍加改动即可应用于任何格式。

在服务器上,我这样做是为了发送一个 excel 文件。

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

response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=exceptions.xlsx")
Run Code Online (Sandbox Code Playgroud)

  • 你是我的英雄!我希望IE能去一个安静的角落死掉。 (2认同)

rol*_*oli 13

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

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

调用该函数,然后下载得到的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()
  })
Run Code Online (Sandbox Code Playgroud)


KJ *_*han 12

大多数答案都缺少几个关键点。

我将尝试在这里进行更深入的解释。

太长了;

如果您正在创建a标签链接并通过浏览器请求启动下载,那么

  1. 总是打电话window.URL.revokeObjectURL(url);。否则可能会出现不必要的内存峰值。

  2. 无需使用 将创建的链接附加到文档正文document.body.appendChild(link);,从而防止以后不必要地删除子项。


有关组件代码和更深入的分析,请进一步阅读

首先是确定您尝试下载数据的 API 端点是公共的还是私有的。您是否可以控制服务器?


如果服务器响应

Content-Disposition: attachment; filename=dummy.pdf
Content-Type: application/pdf
Run Code Online (Sandbox Code Playgroud)

浏览器将始终尝试下载名为“dummy.pdf”的文件


如果服务器响应

Content-Disposition: inline; filename=dummy.pdf
Content-Type: application/pdf
Run Code Online (Sandbox Code Playgroud)

浏览器将首先尝试打开本地文件阅读器(如果名称为“dummy.pdf”),否则它将开始文件下载。


如果服务器没有响应上述 2 个标头

如果未设置下载属性,浏览器(至少是 Chrome)将尝试打开该文件。如果设置,它将下载该文件。如果 url 不是 blob,则文件名将是最后一个路径参数的值。


除此之外,请记住使用Transfer-Encoding: chunkedfrom server 从服务器传输大量数据。Content-Length这将确保客户端知道在没有标头的情况下何时停止读取当前请求

对于私人文件

import { useState, useEffect } from "react";
import axios from "axios";

export default function DownloadPrivateFile(props) {
  const [download, setDownload] = useState(false);

  useEffect(() => {
    async function downloadApi() {
      try {
        // It doesn't matter whether this api responds with the Content-Disposition header or not
        const response = await axios.get(
          "http://localhost:9000/api/v1/service/email/attachment/1mbdoc.docx",
          {
            responseType: "blob", // this is important!
            headers: { Authorization: "sometoken" },
          }
        );
        const url = window.URL.createObjectURL(new Blob([response.data])); // you can mention a type if you wish
        const link = document.createElement("a");
        link.href = url;
        link.setAttribute("download", "dummy.docx"); //this is the name with which the file will be downloaded
        link.click();
        // no need to append link as child to body.
        setTimeout(() => window.URL.revokeObjectURL(url), 0); // this is important too, otherwise we will be unnecessarily spiking memory!
        setDownload(false);
      } catch (e) {} //error handling }
    }

    if (download) {
      downloadApi();
    }
  }, [download]);

  return <button onClick={() => setDownload(true)}>Download Private</button>;
}


Run Code Online (Sandbox Code Playgroud)

对于公共文件

import { useState, useEffect } from "react";
export default function DownloadPublicFile(props) {
  const [download, setDownload] = useState(false);

  useEffect(() => {
    if (download) {
      const link = document.createElement("a");
      link.href =
        "http://localhost:9000/api/v1/service/email/attachment/dummy.pdf";
      link.setAttribute("download", "dummy.pdf");
      link.click();
      setDownload(false);
    }
  }, [download]);

  return <button onClick={() => setDownload(true)}>Download Public</button>;
}

Run Code Online (Sandbox Code Playgroud)

很高兴知道:

  1. 始终控制从服务器下载文件。

  2. 浏览器中的 Axios 在底层使用 XHR,其中不支持响应流。

  3. 使用onDownloadProgressaxios中的方法来实现进度条。

  4. 来自服务器的分块响应不(不能)指示内容长度。因此,如果您在构建进度条时使用它们,您需要某种方法来了解响应大小。

  5. <a>标签链接只能发出 GET HTTP 请求,无法向服务器发送标头或 cookie(非常适合从公共端点下载)

  6. 浏览器请求与代码中发出的 XHR 请求略有不同。

参考:AJAX 请求和常规浏览器请求之间的区别


Nit*_*agi 11

        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.
})
Run Code Online (Sandbox Code Playgroud)


Mul*_*ter 10

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

window.open("<insert URL here>")
Run Code Online (Sandbox Code Playgroud)

您不需要/不需要 axios 来执行此操作;让浏览器做它的事情应该是标准的。

注意:如果您需要下载授权,那么这可能不起作用。我很确定您可以使用 cookie 来授权这样的请求,前提是它在同一个域内,但无论如何,在这种情况下这可能不会立即起作用。


至于是否有可能......不是内置的文件下载机制,没有

  • 授权标头? (15认同)
  • 如果您控制服务器,那么您可以简单地将访问令牌存储为 cookie,浏览器会将其添加到对服务器的任何请求中。https://medium.com/@ryanchenkie_40935/react-authentication-how-to-store-jwt-in-a-cookie-346519310e81 (2认同)

enj*_*syn 5

诀窍是在 中创建一个不可见的锚标记,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>
        )
    }
}
Run Code Online (Sandbox Code Playgroud)

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


归档时间:

查看次数:

104926 次

最近记录:

6 年,1 月 前