GETやPOSTなどの基本的なhttpリクエストにaxiosを使用していますが、うまく機能します。今度はExcelファイルもダウンロードできるようにする必要があります。これはaxiosで可能ですか?もしそうなら、誰かがいくつかのサンプルコードを持っていますか?そうでない場合、同じことを行うためにReactアプリケーションで他に何を使用できますか?
回答:
応答にダウンロード可能なファイルが付属している場合、応答ヘッダーは次のようになります。
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');
});
お役に立てれば :)
responseURL
があります。これは、必要なURLである可能性があります。
より一般的な解決策
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
responseType: 'blob'
response
完了時に変数に保存されます。次にcreateObjectURL
、<a>が移動できるこのデータへのローカルURLを作成します。
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の関係によってかなり複雑になります。一歩ずつ:
トランスポートセキュリティを採用する場合、ブラウザ内で実行される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つのことを実行する必要があります。
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ヘッダーも送信します。
ここにはいくつかの落とし穴があるので、すべての詳細が正しく構成されていることを確認しましょう。
その場合、スケルトン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);
});
content-disposition
代わりにヘッダーを使用することをお勧めしますx-suggested-filename
。
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")
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.
})
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()
})
ユーザーのダウンロードをトリガーするのは非常に単純なJavaScriptコードです。
window.open("<insert URL here>")
この操作にはaxiosは必要ありません。ブラウザにそれをさせるのが標準であるべきです。
注:ダウンロードの認証が必要な場合、これは機能しない可能性があります。同じドメイン内にある場合は、Cookieを使用してこのようなリクエストを承認できると確信していますが、そのような場合はすぐに機能しない可能性があります。
それが可能かどうかについては...組み込みのファイルダウンロードメカニズムではなく、いいえ。
秘訣は、に非表示のアンカータグを作成し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/で見つけることができます。
axios POSTリクエストの場合、リクエストは次のようになります。ここで重要なのはresponseType
、header
フィールドが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;
}
私の答えは完全なハックです-ボタンのようなリンクを作成し、それに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> Excel
</a>
私は優れたVueJを使用しているため、奇妙な注釈が付けられていますが、このソリューションはフレームワークに依存しません。このアイデアは、HTMLベースのデザインで機能します。