如何获取使用Angular $ http下载的文件的名称?

时间:2015-10-09 20:48:34

标签: angularjs http-headers blob

我编写了使用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

11 个答案:

答案 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'
 });
}