我将axios用于GET和POST之类的基本http请求,并且运行良好。现在,我还需要能够下载Excel文件。axios有可能吗?如果是这样,有人可以提供一些示例代码吗?如果没有,我还能在React应用程序中使用什么来做同样的事情?
Answers:
当响应带有可下载的文件时,响应标题将类似于
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和某些安全性方法下载文件时,这实际上甚至更加复杂。为了防止其他人花太多时间来解决这个问题,让我逐步指导您。
您需要做三件事:
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服务器实际发送的6个HTTP标头。如果我们希望服务器为下载建议一个文件名,则必须通知浏览器“允许” JavaScript被授予访问其他标题的权限,在该标题中将传输建议的文件名。
为了便于讨论,让我们假设我们希望服务器在名为X-Suggested-Filename的HTTP标头中传输建议的文件名。HTTP服务器告诉浏览器,这是确定该收到的自定义标题暴露给JavaScript /爱可信与下面的头:
Access-Control-Expose-Headers: X-Suggested-Filename
根据产品的不同,配置HTTP服务器以设置此标头的确切方法也有所不同。
有关这些标准标头的完整说明和详细说明,请参见https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers。
您的服务器端服务实现现在必须执行两件事:
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标头,以供保存文档时使用。
这里有一些陷阱,所以让我们确保正确配置所有细节:
然后,基本的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
header而不是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进行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()
})
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.
})
这是触发用户下载的非常简单的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/。
这为我工作。我在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 });
})
对于axios POST请求,该请求应类似于以下内容:此处的关键是responseType
andheader
字段必须位于Post的第3个参数中。第二个参数是应用程序参数。
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;
}