我编写了使用Angular $ http下载文件的代码。该文件的名称在URL中指定 not 。 URL包含文件的唯一标识符,该标识符从应用程序外部获取。
调用$http.get(myUrl)
时,一切正常;检索文件,我可以在我的回调处理程序中访问它,但我看不到如何获取文件的名称。用Fiddler捕获原始响应,我看到了:
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 54
Content-Type: application/octet-stream
Server: Microsoft-IIS/8.5
Access-Control-Allow-Origin: http://www.example.com/getFile/12345
Access-Control-Allow-Credentials: true
Content-Disposition: attachment; filename=testfile.txt
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 09 Oct 2015 20:25:49 GMT
Lorem ipsum dolar sit amet! The contents of my file!
从上面可以看出,服务器显然是在“Content-Disposition”中发回文件的名称,但我还没有找到在Angular回调中访问它的方法。如何从标题中获取文件的名称?
编辑以回应以下答案:
我之前应该提到我已经尝试过response.headers()
。它返回Object {content-type: "application/octet-stream", cache-control: "private"}
,因此出于某种原因我仍然没有获得Content-Disposition。 response.headers('Content-Disposition')
会返回null
。
答案 0 :(得分:35)
值得一提的是,为了从HTTP标头中获取文件名,提取Content-Disposition
标头是不够的。
您仍需要从此标头值获取filename
属性。
返回的标头值示例:attachment; filename="myFileName.pdf"
。
下面的函数会提取filename="myFileName.pdf"
,然后提取"myFileName.pdf"
,最后删除额外的引号以获取myFileName.pdf
。
您可以使用以下代码段:
function getFileNameFromHttpResponse(httpResponse) {
var contentDispositionHeader = httpResponse.headers('Content-Disposition');
var result = contentDispositionHeader.split(';')[1].trim().split('=')[1];
return result.replace(/"/g, '');
}
答案 1 :(得分:14)
如果您使用CORS,则需要添加" Access-Control-Expose-Headers"到服务器端的响应头。例如:Access-Control-Expose-Headers: x-filename, x-something-else
答案 2 :(得分:10)
Web API:我发现将以下代码行添加到我的IHttpActionResult实现的ExecuteAsync(...)方法中('response'是要返回的HttpResponseMessage):
like||36
dislike||124
Angular:然后我可以按如下方式解析角度的文件名('response'是来自$ http.get的解析后的承诺):
response.Content.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");
答案 3 :(得分:5)
使用response.headers
获取http响应标头:
$http.get(myUrl).then(function (response) {
// extract filename from response.headers('Content-Disposition')
}
答案 4 :(得分:4)
与上述一些答案类似,但使用基本的RegEx是我如何解决它:
let fileName = parseFilenameFromContentDisposition(response.headers('Content-Disposition'));
function parseFilenameFromContentDisposition(contentDisposition) {
if (!contentDisposition) return null;
let matches = /filename="(.*?)"/g.exec(contentDisposition);
return matches && matches.length > 1 ? matches[1] : null;
}
答案 5 :(得分:3)
也许您已经找到了解决方案,但如果其他人遇到此问题,我会发布此答案。
在$ http请求中的成功回调函数中添加这些参数:
$http.get(myUrl).success(function (data, status, headers, config) {
// extract filename from headers('Content-Disposition')
});
答案 6 :(得分:3)
//服务
downloadFile(params: any): Observable<HttpResponse<any>> {
const url = `https://yoururl....etc`;
return this.http.post<HttpResponse<any>>(
url,
params,
{
responseType: 'blob' as 'json',
observe: 'response' as 'body'
})
.pipe(
catchError(err => throwError(err))
);
}
//组件
import * as FileSaver from 'file-saver';
... some code
download(param: any) {
this.service.downloadFile(param).pipe(
).subscribe({
next: (response: any) => {
let fileName = 'file';
const contentDisposition = response.headers.get('Content-Disposition');
if (contentDisposition) {
const fileNameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
const matches = fileNameRegex.exec(contentDisposition);
if (matches != null && matches[1]) {
fileName = matches[1].replace(/['"]/g, '');
}
}
const fileContent = response.body;
FileSaver.saveAs(fileContent, fileName);
},
error: (error) => {
console.log({error});
}
});
}
享受
答案 7 :(得分:0)
success(function(data, status, headers, response,xhr) {
console.log(headers('Content-Disposition'));
}
答案 8 :(得分:0)
这里还有很多其他好的答案-这就是我最终对ASP.NET Core 3.1服务器最适合我的东西,并以其中的许多为指导。
function getFilename() {
const header = response.headers.get("Content-Disposition");
if (!header) {
return null;
}
let matches = /filename=\"?([^;"]+)\"?;?/g.exec(header);
return matches && matches.length > 1 ? matches[1] : null;
}
答案 9 :(得分:0)
此处和 another thread 中的许多答案解决了 OP 的具体情况,或者甚至更为笼统。我相信您应该从 parse
function npm 包中的 content-disposition
开始。但是由于我未能在我的 Angular 12 应用程序中使用这个包(即使尝试类似于 this comment),而且这里的其他答案不能满足我的情况,我又创建了另一个函数。
我的文件名标志情况是 Tyłe;k Mopka.png
,这会产生一个有效的响应头:
content-disposition: attachment; filename="Ty_ek; Mopka.png"; filename*=UTF-8''Ty%C5%82ek%3B%20Mopka.png
我们得到了:一个非 ISO-8859-1 字符、一个空格、一个分号。最后一个特别有趣,不仅是因为参数拆分,还因为百分比编码(decodeURI
不够,我们需要unescape
它)。
export function parseContentDispositionFilename(contentDisposition: string): string {
const filename = getFilename(contentDisposition);
if (filename) {
return unescape(decodeURI(filename));
}
else {
throw new Error('content-disposition filename cannot be empty');
}
}
function getFilename(contentDisposition: string): string | undefined {
const filenames = getFilenameParams(contentDisposition);
if (filenames.filenamestar) {
// RFC 6266 4.1 filename* -> RFC 5987 3.2.1 ext-value
return filenames.filenamestar.replace(/^(?<charset>.+)'(?<language>.*)'(?<filename>.+)$/, '$<filename>');
}
else if (filenames.filename) {
// RFC 6266 4.1 filename (possibly quoted)
return filenames.filename.replace(/^"(?<filename>.+)"$/, '$<filename>');
}
else {
return undefined;
}
}
function getFilenameParams(contentDisposition: string): { filenamestar?: string, filename?: string } {
// Split using ; (if not quoted) and skip the first element since it's `disposition-type`
const [, ...dispositionParams] = contentDisposition.split(/(?!\B"[^"]*);\s(?![^"]*"\B)/);
return {
filenamestar: getParamValue('filename\\*', dispositionParams),
filename: getParamValue('filename', dispositionParams),
};
}
function getParamValue(paramName: string, params: string[]): string | undefined {
const regex = new RegExp('^\\s*' + paramName + '=(?<paramValue>.+)\\s*$', 'i');
return params.find(p => p.match(regex)?.groups?.['paramValue']);
}
this.http.get(/*...*/).pipe(
map(response => {
const contentDisposition = response.headers.get('content-disposition');
if (!contentDisposition) {
throw new Error('content-disposition header not found');
}
const filename = parseContentDispositionFilename(contentDisposition);
/*...*/
答案 10 :(得分:0)
(文件以二进制格式保存在浏览器中。文件名在客户端的Network/header/Content-Disposition,我们需要获取文件名)
In Server-side code:
node js code-
response.setHeader('Access-Control-Expose-Headers','Content-Disposition');
response.download(outputpath,fileName);
In client-side code:
1)appComponent.ts file
import { HttpHeaders } from '@angular/common/http';
this.reportscomponentservice.getReportsDownload(this.myArr).subscribe((event: any) => {
var contentDispositionData= event.headers.get('content-disposition');
let filename = contentDispositionData.split(";")[1].split("=")[1].split('"')[1].trim()
saveAs(event.body, filename);
});
2) service.ts file
import { HttpClient, HttpResponse } from '@angular/common/http';
getReportsDownload(myArr): Observable<HttpResponse<Blob>> {
console.log('Service Page', myArr);
return this.http.post(PowerSimEndPoints.GET_DOWNLOAD_DATA.PROD, myArr, {
observe: 'response',
responseType: 'blob'
});
}