2023-11-23
Angular
00
请注意,本文编写于 751 天前,最后修改于 642 天前,其中某些信息可能已经过时。

目录

下载
下载进度监控

使用Angular框架开发工作中,实现文件下载业务时,我们可以使用ANgular自带的HttpClient。下面我们就封装一下HttpClient实现文件下载,当接口返回文件流正常下载,返回json信息时也能返回,让使用者自行处理。

下载

HttpRequest.ts

import { HttpClient, HttpErrorResponse, HttpHeaders, HttpParams, HttpUrlEncodingCodec } from "@angular/common/http"; import { Injectable, Component } from "@angular/core"; import { throwError } from "rxjs"; import { catchError, map } from "rxjs/operators"; import { environment } from "src/environments/environment"; @Injectable({ providedIn: 'root' }) export class HttpRequest{ public downFileBlobPromise(url: string, data = {}) { let options: any = {} let header: { [name: string]: string } = {} header['Content-Type'] = 'application/x-www-form-urlencoded' header['Accept'] = '*/*' options['headers'] = header options['responseType'] = "blob" options['observe'] = "response" let obj = Object.assign({}, options, { params: data }) return new Promise((resolve, reject) => { this.http.get(url, obj).subscribe(async res => { const txt = await this.convertRes2Blob(res) resolve(txt) }, err => { reject(err) }) }) } private async convertRes2Blob(response: any) { if (!response.headers.has("content-disposition")) { const blob = new Blob([response.body], { type: 'application/octet-stream' }) const resultJson = await this.readBlob(blob) return resultJson } const fileName = this.getFileName(response) const blob = new Blob([response.body], { type: 'application/octet-stream' }) if (typeof window.navigator.msSaveBlob !== 'undefined') { window.navigator.msSaveBlob(blob, fileName) return null } else { const blobUrl = window.URL.createObjectURL(blob) const tempLink = document.createElement('a') tempLink.style.display = 'none' tempLink.href = blobUrl tempLink.setAttribute('download', fileName) document.body.appendChild(tempLink) tempLink.click() document.body.removeChild(tempLink) window.URL.revokeObjectURL(blobUrl) return null } } private getFileName(response: any) { const encode = response.headers.get('content-type')?.match(/charset=(.*)/) ? response.headers.get('content-type').match(/charset=(.*)/)[1] : null let fileName: string = response.headers.get('content-disposition').match(/filename=(.*)/)[1].replaceAll("\"", "") if (encode && encode == 'ISO8859-1') { const fn = escape(fileName) fileName = decodeURI(escape(fileName)).replace(new RegExp("%3A", "gm"), ":") } else { fileName = decodeURI(fileName) } return fileName } private readBlob(blob:Blob){ const f = new FileReader() f.readAsText(blob, "UTF-8") return new Promise((resolve,reject) => { f.onload = (evt: any) => { const re = evt.target.result const result = JSON.parse(re) resolve(result) } f.onerror = (evt:any) => { reject(evt) } }) } }

使用

constructor( private router: Router, private service: AccountIdentifyService, private confirmationService: ConfirmationService, private toast: Toast, private req: HttpRequest, ) { } export() { this.exportLoading = true this.req.downFileBlobPromise(`koa2/download/2.txt`, param).then((res:any) => { this.exportLoading = false if(res){ this.toast.error(res.mess) }else{ this.toast.success("下载成功") } }).catch(err => { this.exportLoading = false this.toast.showError("下载异常") }) }

后端文件下载接口示例,使用koa2写的demo

/** 文件下载 */ router.get("/download/:filename",async function(ctx,next){ const filename = ctx.params.filename; if(filename != "1.txt"){ setTimeout(() => { ctx.body = { resultStat: "1", mess:"文件不存在", }; return }, 5000); } //request里面切出标识符字符串 let requestUrl = ctx.request.originalUrl; //获取资源文件的绝对路径 let filePath = path.resolve(__dirname + "/uploads/" + decodeURI(filename)); console.log(filePath); let resHred = readFile(ctx.headers.range, filePath); ctx.status = resHred.code ctx.set(resHred.head); ctx.set('Content-Disposition', `attachment; filename=${encodeURIComponent(filename)}`); ctx.set('Content-Type', 'application/octet-stream'); let stream = fs.createReadStream(filePath, resHred.code == 200 ? {} : { start: resHred.start, end: resHred.end }); stream.pipe(ctx.res); // //也可使用这种方式。 // stream.on('data', e => ctx.res.write(e)); // // 接收完毕 // stream.on('end', e => ctx.res.end()); ctx.respond = false; return })

下载进度监控

进一步改善我们封装类实现文件下载进度监控

ts
import { HttpClient, HttpEvent, HttpEventType } from "@angular/common/http"; import { Injectable } from "@angular/core"; import { filter, map } from "rxjs/operators"; @Injectable({ providedIn: 'root' }) export class FileHttpRequest { constructor(private http: HttpClient) { } download(url: string, params: any) { let options: any = {} let header: { [name: string]: string } = {} header['Content-Type'] = 'application/x-www-form-urlencoded' header['Accept'] = '*/*' options['headers'] = header options['responseType'] = "arraybuffer" options['observe'] = "events" options["reportProgress"] = true options = Object.assign(options, { params }) console.log(options); return new Promise((resolve, reject) => { this.http.get(url, options).pipe( map(event => this.getEventMessage(event)), filter(f => f != null) ).subscribe(async res => { const txt = await this.getFileFromStream(res) resolve(txt) }, err => { console.log(err); reject(err) }) }) } private getEventMessage(event: any): ArrayBuffer { console.log(event); switch (event.type) { case HttpEventType.DownloadProgress: // 计算出下载进度 const percentDone = Math.round(100 * event.loaded / event.total); console.log(event, percentDone); return null; case HttpEventType.Response: return event; default: return null; } } private getFileName(response: any) { debugger const encode = response.headers.get('content-type')?.match(/charset=(.*)/) ? response.headers.get('content-type').match(/charset=(.*)/)[1] : null let fileName: string = response.headers.get('content-disposition').match(/filename=(.*)/)[1].replaceAll("\"", "") if (encode && encode == 'ISO8859-1') { const fn = escape(fileName) fileName = decodeURI(escape(fileName)).replace(new RegExp("%3A", "gm"), ":") } else { fileName = decodeURI(fileName) } return fileName } private readBlob(blob:Blob){ const f = new FileReader() f.readAsText(blob, "UTF-8") return new Promise((resolve,reject) => { f.onload = (evt: any) => { const re = evt.target.result const result = JSON.parse(re) resolve(result) } f.onerror = (evt:any) => { reject(evt) } }) } private async getFileFromStream(response: any){ if (!response.headers.has("content-disposition")) { const blob = new Blob([response.body], { type: 'application/octet-stream' }) const resultJson = await this.readBlob(blob) return resultJson } const fileName = this.getFileName(response) const blob = new Blob([response.body], { type: 'application/octet-stream' }) if (typeof window.navigator.msSaveBlob !== 'undefined') { window.navigator.msSaveBlob(blob, fileName) return null } else { const blobUrl = window.URL.createObjectURL(blob) const tempLink = document.createElement('a') tempLink.style.display = 'none' tempLink.href = blobUrl tempLink.setAttribute('download', fileName) document.body.appendChild(tempLink) tempLink.click() document.body.removeChild(tempLink) window.URL.revokeObjectURL(blobUrl) return null } } }
如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:千寻

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!