programing

Angular $http로 다운로드 받은 파일 이름을 얻는 방법

megabox 2023. 2. 23. 22:42
반응형

Angular $http로 다운로드 받은 파일 이름을 얻는 방법

Angular $http를 사용하여 파일을 다운로드하는 코드를 작성했습니다.URL에 파일 이름이 지정되지 않았습니다.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"}그래서 어떤 이유로든 콘텐츠 폐기가 되지 않습니다. response.headers('Content-Disposition')돌아온다null.

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

웹 API: IHtpActionResult 구현의 ExecuteAsync(...) 메서드에 다음 코드 행을 추가하는 것이 효과가 있음을 발견했습니다('response'는 반환되는 HttpResponseMessage입니다).

response.Content.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");

각도: 후 다음과 같이 각진 파일명을 해결할 수 있었습니다('response'는 $http.get에서 해결된 약속입니다).

var contentDisposition = response.headers('Content-Disposition');
var filename = contentDisposition.split(';')[1].split('filename')[1].split('=')[1].trim();

CORS를 사용하는 경우 서버 측의 응답 헤더에 "Access-Control-Expose-Headers"를 추가해야 합니다.예를 들어 다음과 같습니다.Access-Control-Expose-Headers: x-filename, x-something-else

위의 답변과 비슷하지만 기본적인 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;
}

사용하다response.headershttp 응답 헤더를 가져오려면:

$http.get(myUrl).then(function (response) {
    // extract filename from response.headers('Content-Disposition')
} 

// 서비스

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});

      }
    });
  }

즐거운 시간 되세요.

이미 해결 방법을 찾으셨겠지만, 다른 사람이 이 문제를 가지고 있다면 제가 이 답변을 올리겠습니다.

$http 요청에서 성공 콜백 함수에 다음 파라미터를 추가합니다.

    $http.get(myUrl).success(function (data, status, headers, config) {
        // extract filename from headers('Content-Disposition')
    });

한다면response.headers('Content-Disposition')null을 반환합니다.사용response.headers.**get**('Content-Disposition');.

이제 @andrew의 스니펫이 잘 작동하게 되었습니다.

success(function(data, status, headers, response,xhr) {
    console.log(headers('Content-Disposition'));
}

이 밖에도 좋은 답변이 많이 있습니다.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;
}

여기와 다른 스레드에 있는 많은 답변은 OP의 특정 사례를 해결하거나 훨씬 더 일반적입니다.npm 패키지의 기능부터 시작하는 것이 좋다고 생각합니다.하지만 이 패키지가 Angular 12 앱에서 작동하지 않고( 코멘트와 유사한 시도에도 불구하고) 다른 답변이 제 사례를 만족시키지 못했기 때문에, 저는 또 다른 기능을 만들었습니다.

는 「 」입니다.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 iso iso iso9, iso iso iso, iso iso iso iso iso iso iso iso iso iso iso.분할되었을 만 아니라 부호화퍼센트 부호화) 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);

/*...*/

(파일은 브라우저에 바이너리 형식으로 저장됩니다.파일명이 클라이언트의 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'
 });
}

언급URL : https://stackoverflow.com/questions/33046930/how-to-get-the-name-of-a-file-downloaded-with-angular-http

반응형