下载文件(使用 Axios 和 Security)
当您想要使用 Axios 和某些安全手段下载文件时,这实际上更加复杂。为了防止其他人花太多时间来解决这个问题,让我引导您完成这个过程。
你需要做三件事:
- 配置您的服务器以允许浏览器查看所需的 HTTP 标头
- 实现服务器端服务,并使其通告下载文件的正确文件类型。
- 实现 Axios 处理程序以在浏览器中触发 FileDownload 对话框
这些步骤大多是可行的 - 但由于浏览器与 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. 实现服务器端服务
您的服务器端服务实现现在必须执行两件事:
- 创建(二进制)文档并将正确的 ContentType 分配给响应
- 分配包含客户端建议文件名的自定义标头 (X-Suggested-Filename)
根据您选择的技术堆栈,可以通过不同的方式完成此操作。我将使用 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. 为接收到的文档实现 Axios 处理程序
这里有一些陷阱,所以让我们确保所有细节都正确配置:
- 服务响应@GET(即HTTP GET),因此axios调用必须是'axios.get(...)'。
- 该文档作为字节流传输,因此您必须告诉 Axios 将响应视为 HTML5 Blob。(即_responseType: 'blob'_)。
- 在本例中,文件保护程序 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);
});