我已经阅读了几本与此相关的StackOverflow帖子,但尚未使它起作用。
我的后端是.NET Core应用程序,它返回byte[]
供我下载PDF。这是返回的数据,首先通过正常调用API,然后将返回类型设置为blob
:
这两个呼叫是这样的:
this.http.get('/my/pdf/url').subscribe(data => console.log(data));
和
this.http.get('/my/pdf/url', { responseType: 'blob' }).subscribe(data => console.log(data));
在两种情况下,我都将返回数据发送到使用FileSaver包保存文件的服务中。对于第一个示例,我尝试像这样保存文件:
saveFile(buffer: any, fileName: string, fileType: string) {
const data: Blob = new Blob([buffer], { type: fileType });
FileSaver.saveAs(data, fileName);
}
它从API中获取数据,将其转换为Blob,然后尝试保存。对于fileType
,我尝试了'application/pdf'
和'application/octet-stream'
,但都没有一个。我试图保存的第二个示例是这样的:
savePdf(blob: Blob, fileName: string) {
FileSaver.saveAs(<any>blob, fileName);
}
但是,这些功能都不起作用。文件已下载,但是当您打开它时,出现错误,并且不显示任何内容。
我不确定还可以尝试什么,但希望有人可以指出正确的方向。
答案 0 :(得分:0)
如果您要从ASP.NET Core WebAPI返回StreamActionResult
(或类似的ActionResult
),那么您应该能够从HTTP响应中检索文件名和文件类型。
export interface DownloadedFile {
blob: Blob;
fileName: string;
}
export function extractFileNameAndBlob(
httpResponse: HttpResponse<ArrayBuffer>
): DownloadedFile {
const headers = httpResponse.headers;
const contentDisposition = headers.get("Content-Disposition");
if (contentDisposition == null) {
throw new Error(`Server Error: Cannot retrieve file name.
Either Content-Dispostion header is not available or it is not exposed using Access-Control-Expose Header.`);
}
const fileNameItem = contentDisposition
.split(";")
.map(item => item.trim())
.find(item => item.toLowerCase().startsWith("filename="));
if (fileNameItem == null) {
throw new Error(`Server didn't send a filename`);
}
let fileName = fileNameItem.split("=")[1];
if (fileName.startsWith('"'))
fileName = fileName.substring(1, fileName.length - 1);
const contentType = headers.get("Content-Type");
const blob = new Blob([httpResponse.body], { type: contentType });
return {
blob: blob,
fileName: fileName
};
}
// Angular Service
@Injectable()
export class DownloadsService {
constructor(private httpClient: HttpClient) {}
public downloadPDF(downloadUrl: string): Observable<DownloadedFile> {
return this.httpClient
.get(downloadUrl, { responseType: "arraybuffer", observe: "response" })
.pipe(
map((httpResponse: HttpResponse<ArrayBuffer>) =>
extractFileNameAndBlob(httpResponse)
)
);
}
}
import { saveAs } from 'file-saver';
private someMethod(): void {
this.downloadsService.downloadPDF('/my/pdf/url').subscribe({
next: downloadedFile => {
saveAs(downloadedFile.blob, downloadedFile.fileName);
}
});
}