import { Injectable, Injector, InjectionToken, Inject } from '@angular/core'; import { NaStartupService } from '@ng-arthur-mobile/core'; import { Observable } from 'rxjs'; import { HttpResponse, HttpClient, HttpRequest } from '@angular/common/http'; import { DOCUMENT } from '@angular/common'; import { tap } from 'rxjs/operators'; import { INaHttpConfig, NaHttpConfig } from './na-http-config'; export const NA_HTTP_CONFIG = new InjectionToken( 'NA_HTTP_CONFIG' ); @Injectable() export class NaHttpService { public static METHOD = ['POST', 'PUT', 'PATCH']; private _httpConfig: INaHttpConfig; constructor(protected injector: Injector, private startupService: NaStartupService, private http: HttpClient, @Inject(DOCUMENT) private _doc: any) { this._httpConfig = new NaHttpConfig(); const injectorConfig = this.injector.get(NA_HTTP_CONFIG, {}); Object.assign(this._httpConfig, injectorConfig); } httpConfig(req: HttpRequest): INaHttpConfig { if (req) { Object.keys(this._httpConfig).forEach(key => { let value = this._httpConfig[key]; if (NaHttpService.METHOD.indexOf(req.method) >= 0) { if (req.body[key]) { value = req.body[key]; } } else { if (req.params.get(key)) { value = req.params.get(key); } } this._httpConfig[key] = value; }); } return this._httpConfig; } get baseUrl(): string { const _baseUrl = this._httpConfig.BASE_URL; if (typeof _baseUrl === 'string') { return this.startupService.get(_baseUrl) || _baseUrl; } else if (_baseUrl instanceof Array) { return this.concat(_baseUrl).substr(1); } } getUrl(key: string, baseUrl: boolean = true) { const value = this.startupService.get(key) || key; if (baseUrl) { return this.concatUrl(this.baseUrl, value); } return value; } concatUrl(urlPrefix: string, urlSuffix: string) { if (urlPrefix == null && urlSuffix != null) { return urlSuffix; } if (urlPrefix != null && urlSuffix == null) { return urlPrefix; } if (typeof urlPrefix !== 'string') { throw new Error('merge the url error. use string, now: ' + JSON.stringify(urlPrefix)); } if (typeof urlSuffix !== 'string') { throw new Error('merge the url error. use string, now: ' + JSON.stringify(urlSuffix)); } if (urlPrefix.endsWith('/') && urlSuffix.startsWith('/')) { return urlPrefix + urlSuffix.substr(1); } if (urlPrefix.endsWith('/') || urlSuffix.startsWith('/')) { return urlPrefix + urlSuffix; } return urlPrefix + '/' + urlSuffix; } private concat(args: string[]): string { let newStr = ''; args.forEach(arg => { newStr = this.concatUrl(newStr, this.startupService.get(arg) || arg); }); return newStr; } download(url: string, body: any, filename?: string): Observable> { return this.http.post(url, body, { observe: 'response', responseType: 'blob' }).pipe( tap(data => { const headers = data.headers; const blob = new Blob([data.body], {type: headers.get('Content-Type')}); if (filename) { this.innerDownload(filename, blob); } else { // decodeURIComponent 解决中文乱码 const contentDisposition = headers.get('Content-Disposition'); if (contentDisposition) { filename = decodeURIComponent(contentDisposition.split('filename=')[1]); this.innerDownload(filename, blob); } else { console.error('download failed. filename is null, Please check the \'access-control-expose-headers: content-disposition\' and headers[\'Content-Disposition\'] filename='); } } } ) ); } private innerDownload(filename: string, blob: Blob) { if ('msSaveOrOpenBlob' in navigator) {// IE导出 window.navigator.msSaveOrOpenBlob(blob, filename); } else { const link = this._doc.createElement('a'); link.setAttribute('href', window.URL.createObjectURL(blob)); link.setAttribute('download', filename); link.style.visibility = 'hidden'; this._doc.body.appendChild(link); link.click(); this._doc.body.removeChild(link); } } }