axiosを使用してファイルをダウンロードする方法


124

GETやPOSTなどの基本的なhttpリクエストにaxiosを使用していますが、うまく機能します。今度はExcelファイルもダウンロードできるようにする必要があります。これはaxiosで可能ですか?もしそうなら、誰かがいくつかのサンプルコードを持っていますか?そうでない場合、同じことを行うためにReactアプリケーションで他に何を使用できますか?


このソリューションを使用して、Excelファイルをダウンロードできます。stackoverflow.com/questions/57127361/...
。メリーNazrulイスラム

回答:


107

応答にダウンロード可能なファイルが付属している場合、応答ヘッダーは次のようになります。

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モジュールを使用することもできます。Githubリポジトリへのリンク

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

Axios({
  url: 'http://localhost/downloadFile',
  method: 'GET',
  responseType: 'blob', // Important
}).then((response) => {
    FileDownload(response.data, 'report.csv');
});

お役に立てれば :)


1
ありがとうございました。これがajaxスタイルかどうか教えてください。ページをブロックしないのが良いでしょう。
David Choi

はい、ページはブロックされません。URLをpropとしてそのコンポーネントに渡すと、ファイルが自動的にダウンロードされます。何もする必要はありません。
Hardik Modha 2017年

もう1つ質問があります。私の場合、ダウンロードされるファイルは、いくつかのパラメーターが渡されて動的に作成されます。そのため、実際には一貫した場所がありません。このタイプのシナリオで送信するURLは何ですか?たとえば、axios.post( 'api / getmyexcelfile'、params);を呼び出した場合です。
David Choi

この答えで述べたように。axios応答オブジェクトでは、リクエスト内にAsという名前のフィールドresponseURLがあります。これは、必要なURLである可能性があります。
Hardik Modha 2017年

1
私はこれに従い、ファイルをダウンロードすることができました。しかし、ファイルは壊れています(機能しません)。ただし、リダイレクト(window.location.href)を使用すると、ファイルがダウンロードされ、完全に機能します。誰かがこれを手伝ってくれませんか?(stackoverflow.com/questions/56306008/...
Thidasa Pankaja

125

より一般的な解決策

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


12
解決していただきありがとうございます。他の人へのほんの少しの注意:これは多くのユースケースで機能するかもしれませんが、ファイルサイズが大きい場合はダウンロードの進行状況を確認できません。また、ブラウザで余分なメモリが必要になります。他のソリューションでほのめかされているが、詳しく説明されていないように、一般的なアプローチは、ヘッダー「Content-Disposition:attachment;」を使用することです。したがって、ブラウザはそれをネイティブダウンロードとして扱います(前述のダウンロードの進行状況+ディスクへの直接ダウンロード)。
ジョン・リー・

サーバー側では、Content-Despositionヘッダーを設定しても、ダウンロードの進行が許可されていないようです。
huggie

4
これをありがとう。なぜファイルの内容が正しく表示されないのか疑問に思っていました。私が行方不明になった判明responseType: 'blob'
AliAvci

その後、唯一のブラウザは、ダウンロードファイルに保存しようとしていないが、ファイルがメモリ内のブロブとしてダウンロードされるだけ(実際には、ダウンロードの進行状況を示すブラウザなし)このダウンロード最初のメモリへの応答としてファイルをん...
リッキーを-U20年

@ Ricky-Uはい、その通りです。xhrリクエストが送信され、レスポンスが到着すると、メモリにバッファリングされ、後でresponse完了時に変数に保存されます。次にcreateObjectURL、<a>が移動できるこのデータへのローカルURLを作成します。
Viney

50

ファイルのダウンロード(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

これらの手順はほとんど実行可能ですが、ブラウザとCORSの関係によってかなり複雑になります。一歩ずつ:

1.(HTTP)サーバーを構成します

トランスポートセキュリティを採用する場合、ブラウザ内で実行されるJavaScriptは、[設計上] HTTPサーバーによって実際に送信されるHTTPヘッダーのうち6つにしかアクセスできません。サーバーにダウンロード用のファイル名を提案させたい場合は、提案されたファイル名が転送される他のヘッダーへのアクセスをJavaScriptが許可しても「OK」であることをブラウザーに通知する必要があります。

議論のために、サーバーが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.サーバー側サービスを実装します

サーバー側のサービス実装は、次の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

これは、選択したテクノロジースタックに応じてさまざまな方法で実行されます。Excelレポートを発行するJavaEE7標準を使用して例をスケッチします。

@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.受信したドキュメントのAxiosハンドラーを実装します

ここにはいくつかの落とし穴があるので、すべての詳細が正しく構成されていることを確認しましょう。

  1. サービスは@GET(つまり、HTTP GET)に応答するため、axios呼び出しは「axios.get(...)」である必要があります。
  2. ドキュメントはバイトストリームとして送信されるため、応答をHTML5Blobとして扱うようにaxiosに指示する必要があります。(つまり、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);
    });

21
「FileSaver」とは何ですか?
メインパル

6
これは、ダウンロードファイルを処理するためのライブラリです。github.com/ eligrey / FileSaver.js /#filesaverjs–
Radi

3
これは機能しますが、のcontent-disposition代わりにヘッダーを使用することをお勧めしますx-suggested-filename
Rosdi Kasim 2018

14

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")

8
        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.
})

8

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()
  })

7

ユーザーのダウンロードをトリガーするのは非常に単純なJavaScriptコードです。

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

この操作にはaxiosは必要ありません。ブラウザにそれをさせるのが標準であるべきです。

注:ダウンロードの認証が必要な場合、これは機能しない可能性があります。同じドメイン内にある場合は、Cookieを使用してこのようなリクエストを承認できると確信していますが、そのような場合はすぐに機能しない可能性があります。


それが可能かどうかについては...組み込みのファイルダウンロードメカニズムではなく、いいえ


12
承認ヘッダー?
EjazKarim19年

トークンを送信する必要がある場合はどうなりますか?
user38083 0720

サーバーを制御している場合は、アクセストークンをCookieとして保存するだけで、ブラウザがサーバーへのリクエストに追加します。medium.com/@ryanchenkie_40935/...
マルチハンター

1
@CharithJayasankaはい、そう思います。
マルチハンター

2

秘訣は、に非表示のアンカータグを作成し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/で見つけることができます


-1

axios POSTリクエストの場合、リクエストは次のようになります。ここで重要なのはresponseTypeheaderフィールドがPostの3番目のパラメーターに含まれている必要があるということです。2番目のパラメーターはアプリケーションパラメーターです。

export const requestDownloadReport = (requestParams) => async dispatch => { 
  let response = null;
  try {
    response = await frontEndApi.post('createPdf', {
      requestParams: requestParams,
    },
    {
      responseType: 'arraybuffer', // important...because we need to convert it to a blob. If we don't specify this, response.data will be the raw data. It cannot be converted to blob directly.
      headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/pdf'
      }
  });          
  }
  catch(err) {
    console.log('[requestDownloadReport][ERROR]', err);
    return err
  }

  return response;
}

-4

私の答えは完全なハックです-ボタンのようなリンクを作成し、それに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>

私は優れたVueJを使用しているため、奇妙な注釈が付けられていますが、このソリューションはフレームワークに依存しません。このアイデアは、HTMLベースのデザインで機能します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.