angular 11 怎么获取 Content-Disposition

Fork Me On Github

需求

angular 实现文件下载功能, 默认只能在前端代码中手动添加文件类型及文件名。

ts
                                        
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'));
        });
    }

}
12345678910111213141516171819202122232425262728293031323334353637383940

使用

ts
    
private downloadService: DownloadService

this.downloadService.export('http://localhost/export', {}, '流水记录.xlsx');
1234

突然想到

在响应头中已经有了文件类型和文件名,那么是否可以直接获取呢?

解决

关键是响应头中的 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: Content-Disposition
1

基础知识

响应首部 Access-Control-Expose-Headers 列出了哪些首部可以作为响应的一部分暴露给外部。

默认情况下,只有七种 simple response headers (简单响应首部)可以暴露给外部:

  1. Cache-Control
  2. Content-Language
  3. Content-Length
  4. Content-Type
  5. Expires
  6. Last-Modified
  7. Pragma

如果想要让客户端可以访问到其他的首部信息,可以将它们在 Access-Control-Expose-Headers 里面列出来。

 
Access-Control-Expose-Headers: <header-name>, <header-name>, ...
1

多个用英文逗号分隔

来源

最终代码

ts
                                                   
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编码
    }

}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
点击查看全文
标签: angular
0 757 0
在 angular 项目中实现对页面的访问控制
按下回车键,焦点移动到下一个表单或提交表单
使用ng-template 显示tree结构数据
使用 ViewContainerRef.createComponent 替代 ComponentFactoryResolver
angular 12使用 KaTex 显示 AsciiMath 格式的公式