Angular: 如何从HttpClient 下载文件?
Angular: How to download a file from HttpClient?
我需要从我的后端下载一个 excel,它返回了一个文件。
当我执行请求时出现错误:
TypeError: You provided 'undefined' where a stream was expected. You
can provide an Observable, Promise, Array, or Iterable.
我的代码是:
this.http.get(`${environment.apiUrl}/...`)
.subscribe(response => this.downloadFile(response, "application/ms-excel"));
我尝试了 get 和 map(...) 但没有成功。
详情:angular 5.2
参考文献:
import { HttpClient } from '@angular/common/http';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/finally';
import 'rxjs/add/operator/map'
import 'rxjs/add/operator/catch';
响应的内容类型:
Content-Type: application/ms-excel
怎么了?
尝试这样的事情:
type: application/ms-excel
/**
* used to get file from server
*/
this.http.get(`${environment.apiUrl}`,{
responseType: 'arraybuffer',headers:headers}
).subscribe(response => this.downLoadFile(response, "application/ms-excel"));
/**
* Method is use to download file.
* @param data - Array Buffer data
* @param type - type of the document.
*/
downLoadFile(data: any, type: string) {
let blob = new Blob([data], { type: type});
let url = window.URL.createObjectURL(blob);
let pwa = window.open(url);
if (!pwa || pwa.closed || typeof pwa.closed == 'undefined') {
alert( 'Please disable your Pop-up blocker and try again.');
}
}
从后端返回带有文件类型的 Blob。以下函数将接受任何文件类型和弹出式下载 window:
downloadFile(route: string, filename: string = null): void{
const baseUrl = 'http://myserver/index.php/api';
const token = 'my JWT';
const headers = new HttpHeaders().set('authorization','Bearer '+token);
this.http.get(baseUrl + route,{headers, responseType: 'blob' as 'json'}).subscribe(
(response: any) =>{
let dataType = response.type;
let binaryData = [];
binaryData.push(response);
let downloadLink = document.createElement('a');
downloadLink.href = window.URL.createObjectURL(new Blob(binaryData, {type: dataType}));
if (filename)
downloadLink.setAttribute('download', filename);
document.body.appendChild(downloadLink);
downloadLink.click();
}
)
}
在花了很多时间搜索对这个答案的回应之后:如何从我的 API restful 服务器下载一个简单的图像,用 Node.js 编写成 Angular component app,终于在这个网找到了漂亮的答案Angular HttpClient Blob。它主要包括:
API Node.js restful:
/* After routing the path you want ..*/
public getImage( req: Request, res: Response) {
// Check if file exist...
if (!req.params.file) {
return res.status(httpStatus.badRequest).json({
ok: false,
msg: 'File param not found.'
})
}
const absfile = path.join(STORE_ROOT_DIR,IMAGES_DIR, req.params.file);
if (!fs.existsSync(absfile)) {
return res.status(httpStatus.badRequest).json({
ok: false,
msg: 'File name not found on server.'
})
}
res.sendFile(path.resolve(absfile));
}
Angular 6 个经过测试的组件服务(在我的案例中是 EmployeeService):
downloadPhoto( name: string) : Observable<Blob> {
const url = environment.api_url + '/storer/employee/image/' + name;
return this.http.get(url, { responseType: 'blob' })
.pipe(
takeWhile( () => this.alive),
filter ( image => !!image));
}
模板
<img [src]="" class="custom-photo" #photo>
组件订阅者和使用:
@ViewChild('photo') image: ElementRef;
public LoadPhoto( name: string) {
this._employeeService.downloadPhoto(name)
.subscribe( image => {
const url= window.URL.createObjectURL(image);
this.image.nativeElement.src= url;
}, error => {
console.log('error downloading: ', error);
})
}
我在使用 post 搜索“rxjs 下载文件”时最终来到这里。
这是我的最终产品。它使用服务器响应中给出的文件名和类型。
import { ajax, AjaxResponse } from 'rxjs/ajax';
import { map } from 'rxjs/operators';
downloadPost(url: string, data: any) {
return ajax({
url: url,
method: 'POST',
responseType: 'blob',
body: data,
headers: {
'Content-Type': 'application/json',
'Accept': 'text/plain, */*',
'Cache-Control': 'no-cache',
}
}).pipe(
map(handleDownloadSuccess),
);
}
handleDownloadSuccess(response: AjaxResponse) {
const downloadLink = document.createElement('a');
downloadLink.href = window.URL.createObjectURL(response.response);
const disposition = response.xhr.getResponseHeader('Content-Disposition');
if (disposition) {
const filenameRegex = /filename[^;=\n]*=((['"]).*?|[^;\n]*)/;
const matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) {
const filename = matches[1].replace(/['"]/g, '');
downloadLink.setAttribute('download', filename);
}
}
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
}
我花了一些时间来实现其他响应,因为 我使用的是 Angular 8(最多测试 13)。我最终得到了以下代码(深受 Hasan 的启发)。
请注意,要设置名称,header Access-Control-Expose-Headers
必须包含 Content-Disposition
。要在 django RF 中设置它:
http_response = HttpResponse(package, content_type='application/javascript')
http_response['Content-Disposition'] = 'attachment; filename="{}"'.format(filename)
http_response['Access-Control-Expose-Headers'] = "Content-Disposition"
在angular中:
// component.ts
// getFileName not necessary, you can just set this as a string if you wish
getFileName(response: HttpResponse<Blob>) {
let filename: string;
try {
const contentDisposition: string = response.headers.get('content-disposition');
const r = /(?:filename=")(.+)(?:;")/
filename = r.exec(contentDisposition)[1];
}
catch (e) {
filename = 'myfile.txt'
}
return filename
}
downloadFile() {
this._fileService.downloadFile(this.file.uuid)
.subscribe(
(response: HttpResponse<Blob>) => {
let filename: string = this.getFileName(response)
let binaryData = [];
binaryData.push(response.body);
let downloadLink = document.createElement('a');
downloadLink.href = window.URL.createObjectURL(new Blob(binaryData, { type: 'blob' }));
downloadLink.setAttribute('download', filename);
document.body.appendChild(downloadLink);
downloadLink.click();
}
)
}
// service.ts
downloadFile(uuid: string) {
return this._http.get<Blob>(`${environment.apiUrl}/api/v1/file/${uuid}/package/`, { observe: 'response', responseType: 'blob' as 'json' })
}
使用 Blob
作为 img
的来源:
模板:
<img [src]="url">
分量:
public url : SafeResourceUrl;
constructor(private http: HttpClient, private sanitizer: DomSanitizer) {
this.getImage('/api/image.jpg').subscribe(x => this.url = x)
}
public getImage(url: string): Observable<SafeResourceUrl> {
return this.http
.get(url, { responseType: 'blob' })
.pipe(
map(x => {
const urlToBlob = window.URL.createObjectURL(x) // get a URL for the blob
return this.sanitizer.bypassSecurityTrustResourceUrl(urlToBlob); // tell Anuglar to trust this value
}),
);
}
的进一步参考
使用从 API(Excel 文件)中输出的 Blob
并调整了@gabrielrincon 的回答
downloadExcel(): void {
const payload = {
order: 'test',
};
this.service.downloadExcel(payload)
.subscribe((res: any) => {
this.blobToFile(res, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Export.xlsx");
});}
blob转文件常用函数
blobToFile(data: any, type: string, fileName: string) {
const a = document.createElement('a');
document.body.appendChild(a);
a.style.display = 'none';
const blob = new Blob([data], { type: type });
const url = window.URL.createObjectURL(blob);
a.href = url; a.download = fileName; a.click();
window.URL.revokeObjectURL(url);}
在 blob 到文件函数中,我们期望第一个参数作为我们的 blob 数据、文件类型和传递文件名,包括扩展名 1。我们正在创建一个 html 标记元素 2。然后我们附加html 中的元素 3. 然后隐藏 a 标签元素 4. 然后用文件和类型创建新的 blob 对象 5. 我们将把 blob 对象转换为 URL 6. 然后附加 URL到我们的 a 标签 7 的 href 属性。我们正在 window 中打开我们的 URL 所以它会下载
可能是我来晚了。但@Hasan 的最后回答非常棒。
我只是做了一些小改动(这不是接受 headers 所以删除了)就成功了。
downloadFile(route: string, filename: string = null): void {
// const baseUrl = 'http://myserver/index.php/api';
this.http.get(route, { responseType: 'blob' }).subscribe(
(response: any) => {
let dataType = response.type;
let binaryData = [];
binaryData.push(response);
let downloadLink = document.createElement('a');
downloadLink.href = window.URL.createObjectURL(new Blob(binaryData, { type: dataType }));
if (filename) {
downloadLink.setAttribute('download', filename);
}
document.body.appendChild(downloadLink);
downloadLink.click();
}
)
}
如果你的后端 returns attachment
标志和 filename
属性 在它的 Content-Disposition
,你可以简单地使这个最简单的 javascript 打电话。
window.location = `${environment.apiUrl}/...`;
浏览器将下载文件而不改变当前页面。
我需要从我的后端下载一个 excel,它返回了一个文件。
当我执行请求时出现错误:
TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
我的代码是:
this.http.get(`${environment.apiUrl}/...`)
.subscribe(response => this.downloadFile(response, "application/ms-excel"));
我尝试了 get 和 map(...) 但没有成功。
详情:angular 5.2
参考文献:
import { HttpClient } from '@angular/common/http';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/finally';
import 'rxjs/add/operator/map'
import 'rxjs/add/operator/catch';
响应的内容类型:
Content-Type: application/ms-excel
怎么了?
尝试这样的事情:
type: application/ms-excel
/**
* used to get file from server
*/
this.http.get(`${environment.apiUrl}`,{
responseType: 'arraybuffer',headers:headers}
).subscribe(response => this.downLoadFile(response, "application/ms-excel"));
/**
* Method is use to download file.
* @param data - Array Buffer data
* @param type - type of the document.
*/
downLoadFile(data: any, type: string) {
let blob = new Blob([data], { type: type});
let url = window.URL.createObjectURL(blob);
let pwa = window.open(url);
if (!pwa || pwa.closed || typeof pwa.closed == 'undefined') {
alert( 'Please disable your Pop-up blocker and try again.');
}
}
从后端返回带有文件类型的 Blob。以下函数将接受任何文件类型和弹出式下载 window:
downloadFile(route: string, filename: string = null): void{
const baseUrl = 'http://myserver/index.php/api';
const token = 'my JWT';
const headers = new HttpHeaders().set('authorization','Bearer '+token);
this.http.get(baseUrl + route,{headers, responseType: 'blob' as 'json'}).subscribe(
(response: any) =>{
let dataType = response.type;
let binaryData = [];
binaryData.push(response);
let downloadLink = document.createElement('a');
downloadLink.href = window.URL.createObjectURL(new Blob(binaryData, {type: dataType}));
if (filename)
downloadLink.setAttribute('download', filename);
document.body.appendChild(downloadLink);
downloadLink.click();
}
)
}
在花了很多时间搜索对这个答案的回应之后:如何从我的 API restful 服务器下载一个简单的图像,用 Node.js 编写成 Angular component app,终于在这个网找到了漂亮的答案Angular HttpClient Blob。它主要包括:
API Node.js restful:
/* After routing the path you want ..*/
public getImage( req: Request, res: Response) {
// Check if file exist...
if (!req.params.file) {
return res.status(httpStatus.badRequest).json({
ok: false,
msg: 'File param not found.'
})
}
const absfile = path.join(STORE_ROOT_DIR,IMAGES_DIR, req.params.file);
if (!fs.existsSync(absfile)) {
return res.status(httpStatus.badRequest).json({
ok: false,
msg: 'File name not found on server.'
})
}
res.sendFile(path.resolve(absfile));
}
Angular 6 个经过测试的组件服务(在我的案例中是 EmployeeService):
downloadPhoto( name: string) : Observable<Blob> {
const url = environment.api_url + '/storer/employee/image/' + name;
return this.http.get(url, { responseType: 'blob' })
.pipe(
takeWhile( () => this.alive),
filter ( image => !!image));
}
模板
<img [src]="" class="custom-photo" #photo>
组件订阅者和使用:
@ViewChild('photo') image: ElementRef;
public LoadPhoto( name: string) {
this._employeeService.downloadPhoto(name)
.subscribe( image => {
const url= window.URL.createObjectURL(image);
this.image.nativeElement.src= url;
}, error => {
console.log('error downloading: ', error);
})
}
我在使用 post 搜索“rxjs 下载文件”时最终来到这里。
这是我的最终产品。它使用服务器响应中给出的文件名和类型。
import { ajax, AjaxResponse } from 'rxjs/ajax';
import { map } from 'rxjs/operators';
downloadPost(url: string, data: any) {
return ajax({
url: url,
method: 'POST',
responseType: 'blob',
body: data,
headers: {
'Content-Type': 'application/json',
'Accept': 'text/plain, */*',
'Cache-Control': 'no-cache',
}
}).pipe(
map(handleDownloadSuccess),
);
}
handleDownloadSuccess(response: AjaxResponse) {
const downloadLink = document.createElement('a');
downloadLink.href = window.URL.createObjectURL(response.response);
const disposition = response.xhr.getResponseHeader('Content-Disposition');
if (disposition) {
const filenameRegex = /filename[^;=\n]*=((['"]).*?|[^;\n]*)/;
const matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) {
const filename = matches[1].replace(/['"]/g, '');
downloadLink.setAttribute('download', filename);
}
}
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
}
我花了一些时间来实现其他响应,因为 我使用的是 Angular 8(最多测试 13)。我最终得到了以下代码(深受 Hasan 的启发)。
请注意,要设置名称,header Access-Control-Expose-Headers
必须包含 Content-Disposition
。要在 django RF 中设置它:
http_response = HttpResponse(package, content_type='application/javascript')
http_response['Content-Disposition'] = 'attachment; filename="{}"'.format(filename)
http_response['Access-Control-Expose-Headers'] = "Content-Disposition"
在angular中:
// component.ts
// getFileName not necessary, you can just set this as a string if you wish
getFileName(response: HttpResponse<Blob>) {
let filename: string;
try {
const contentDisposition: string = response.headers.get('content-disposition');
const r = /(?:filename=")(.+)(?:;")/
filename = r.exec(contentDisposition)[1];
}
catch (e) {
filename = 'myfile.txt'
}
return filename
}
downloadFile() {
this._fileService.downloadFile(this.file.uuid)
.subscribe(
(response: HttpResponse<Blob>) => {
let filename: string = this.getFileName(response)
let binaryData = [];
binaryData.push(response.body);
let downloadLink = document.createElement('a');
downloadLink.href = window.URL.createObjectURL(new Blob(binaryData, { type: 'blob' }));
downloadLink.setAttribute('download', filename);
document.body.appendChild(downloadLink);
downloadLink.click();
}
)
}
// service.ts
downloadFile(uuid: string) {
return this._http.get<Blob>(`${environment.apiUrl}/api/v1/file/${uuid}/package/`, { observe: 'response', responseType: 'blob' as 'json' })
}
使用 Blob
作为 img
的来源:
模板:
<img [src]="url">
分量:
public url : SafeResourceUrl;
constructor(private http: HttpClient, private sanitizer: DomSanitizer) {
this.getImage('/api/image.jpg').subscribe(x => this.url = x)
}
public getImage(url: string): Observable<SafeResourceUrl> {
return this.http
.get(url, { responseType: 'blob' })
.pipe(
map(x => {
const urlToBlob = window.URL.createObjectURL(x) // get a URL for the blob
return this.sanitizer.bypassSecurityTrustResourceUrl(urlToBlob); // tell Anuglar to trust this value
}),
);
}
的进一步参考
使用从 API(Excel 文件)中输出的 Blob
并调整了@gabrielrincon 的回答
downloadExcel(): void {
const payload = {
order: 'test',
};
this.service.downloadExcel(payload)
.subscribe((res: any) => {
this.blobToFile(res, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Export.xlsx");
});}
blob转文件常用函数
blobToFile(data: any, type: string, fileName: string) {
const a = document.createElement('a');
document.body.appendChild(a);
a.style.display = 'none';
const blob = new Blob([data], { type: type });
const url = window.URL.createObjectURL(blob);
a.href = url; a.download = fileName; a.click();
window.URL.revokeObjectURL(url);}
在 blob 到文件函数中,我们期望第一个参数作为我们的 blob 数据、文件类型和传递文件名,包括扩展名 1。我们正在创建一个 html 标记元素 2。然后我们附加html 中的元素 3. 然后隐藏 a 标签元素 4. 然后用文件和类型创建新的 blob 对象 5. 我们将把 blob 对象转换为 URL 6. 然后附加 URL到我们的 a 标签 7 的 href 属性。我们正在 window 中打开我们的 URL 所以它会下载
可能是我来晚了。但@Hasan 的最后回答非常棒。
我只是做了一些小改动(这不是接受 headers 所以删除了)就成功了。
downloadFile(route: string, filename: string = null): void { // const baseUrl = 'http://myserver/index.php/api'; this.http.get(route, { responseType: 'blob' }).subscribe( (response: any) => { let dataType = response.type; let binaryData = []; binaryData.push(response); let downloadLink = document.createElement('a'); downloadLink.href = window.URL.createObjectURL(new Blob(binaryData, { type: dataType })); if (filename) { downloadLink.setAttribute('download', filename); } document.body.appendChild(downloadLink); downloadLink.click(); } ) }
如果你的后端 returns attachment
标志和 filename
属性 在它的 Content-Disposition
,你可以简单地使这个最简单的 javascript 打电话。
window.location = `${environment.apiUrl}/...`;
浏览器将下载文件而不改变当前页面。