需求
在 angular
实现文件下载功能, 默认只能在前端代码中手动添加文件类型及文件名。
export class DownloadService {
constructor(private http: HttpClient) { }
/**
* Blob请求
*/
public requestBlob(url: string, data?: any): Observable<any> {
return this.http.request('post', url, {
body: data,
observe: 'response',
responseType: 'blob',
});
}
/**
* Blob文件转换下载
*/
public downFile(result: any, fileName: string, fileType?: string) {
const data = result.body;
const blob = new Blob([data], {
type: fileType || data.type,
});
const objectUrl = URL.createObjectURL(blob);
const a = document.createElement('a');
a.setAttribute('style', 'display:none');
a.setAttribute('href', objectUrl);
a.setAttribute('download', fileName);
a.click();
URL.revokeObjectURL(objectUrl);
}
public export(url: string, data: any, fileName: string, fileType?: any) {
this.requestBlob(url, data).subscribe(result => {
const headers = result.headers as HttpHeaders;
this.downFile(result, fileName,
fileType || headers.get('Content-Type'));
});
}
}
使用
private downloadService: DownloadService
this.downloadService.export('http://localhost/export', {}, '流水记录.xlsx');
突然想到
在响应头中已经有了文件类型和文件名,那么是否可以直接获取呢?
解决
关键是响应头中的 Access-Control-Expose-Headers
在 angular issue 中就有人提处理这个问题,
并且给出了解决方法
Unable to view 'Content-Disposition' headers in Angular4 GET response
里面提供了一个 Java
的解决方案
翻译成普通语言就是:
需要在服务端响应头中加 Access-Control-Expose-Headers
加上 Content-Disposition
值
基础知识
响应首部 Access-Control-Expose-Headers
列出了哪些首部可以作为响应的一部分暴露给外部。
默认情况下,只有七种 simple response headers (简单响应首部)可以暴露给外部:
- Cache-Control
- Content-Language
- Content-Length
- Content-Type
- Expires
- Last-Modified
- Pragma
如果想要让客户端可以访问到其他的首部信息,可以将它们在 Access-Control-Expose-Headers
里面列出来。
多个用英文逗号分隔
【来源】
最终代码
export class DownloadService {
constructor(private http: HttpClient) { }
/**
* Blob请求
*/
public requestBlob(url: string, data?: any): Observable<HttpResponse<Blob>> {
return this.http.request('post', url, {
body: data,
observe: 'response',
responseType: 'blob',
});
}
/**
* Blob文件转换下载
*/
public downFile(result: HttpResponse<Blob>, fileName?: string, fileType?: string) {
fileName = this.parseFileName(result.headers.get('Content-Disposition'), fileName);
if (!fileName) {
console.log('fileName error');
return;
}
const data = result.body;
const blob = new Blob([data], {
type: fileType || data.type,
});
const objectUrl = URL.createObjectURL(blob);
const a = document.createElement('a');
a.setAttribute('style', 'display:none');
a.setAttribute('href', objectUrl);
a.setAttribute('download', fileName);
a.click();
URL.revokeObjectURL(objectUrl);
}
public export(url: string, data: any, fileName?: string, fileType?: any) {
this.requestBlob(url, data).subscribe((res: HttpResponse<Blob>) => {
this.downFile(res, fileName, fileType);
});
}
private parseFileName(header: string, def?: string): string {
if (!header) {
return def;
}
const name = header.split(';')[1].trim().split('=')[1];
return decodeURI(name.replace(/"/g, '')); // 注意中文请在服务端添加url编码
}
}
转载请保留原文链接: https://zodream.cn/blog/id/201.html