파일 다운로드 후 처리를 수행하는 Javascript

페이지 업데이트 :
페이지 생성 날짜 :

동작 검증 환경

비주얼 스튜디오
  • 비주얼 스튜디오 2022
ASP.NET 코어
  • 8.0(Razpr 페이지, MVC)
웹 브라우저
  • 엣지 119

운영 환경

Visual Studio(서버 프로그램도 포함하는 경우)
  • 비주얼 스튜디오 2022
ASP.NET Core(서버 프로그램도 포함된 경우)
  • 8.0(Razpr 페이지, MVC)
웹 브라우저
  • 가장자리
  • 구글 크롬
  • 다른 브라우저(모두 선택되지 않음)

(*이 팁의 본문은 클라이언트 측 프로세스이므로 서버 측은 무엇이든 될 수 있습니다)

처음에

이 팁의 주요 초점은 클라이언트 프로그램(Javascript)이며 서버 프로그램은 파일을 다운로드하기 위해서만 존재합니다. 따라서 파일을 다운로드할 수 있는 한 서버 프로그램이 무엇인지는 중요하지 않습니다.

사용자가 서버에서 액세스할 때 파일을 다운로드하도록 합니다.

Mr./Ms.는 요청을 받았을 때 파일을 다운로드할 수 있습니다. 이때 다운로드의 시작과 끝을 쉽게 이해할 수 있도록 일부러 서버에서 일정 시간 동안 기다립니다.

Razor Pages 및 MVC의 서버 쪽에서 발생하는 작업은 다음과 같습니다. Web API와 같은 다른 프로젝트에서 구현할 수 있습니다.

Razor Pages : 페이지/Index.cshtml.cs

// 省略

namespace DownloadCompleteNotifyRazorPages.Pages
{
  public class IndexModel : PageModel
  {
    // 省略

    /// <summary>時間をかけてファイルをダウンロードします。</summary>
    public async Task<IActionResult> OnGetDownload()
    {
      // ダウンロード開始と完了を明確にする目的で待機を入れる
      await Task.Delay(5000);

      // 適当にファイルを作って返す
      var fileSize = 10_000_000;
      var sb = new System.Text.StringBuilder(fileSize);
      for (int i = 0; i < fileSize; i++) sb.Append('a');
      using var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(sb.ToString()));
      return File(stream.ToArray(), "text/plain", $"ダウンロード.txt");
    }
  }
}

MVC : Coletollers / HomeController.cs

// 省略

namespace DownloadCompleteNotifyMvc.Controllers
{
  public class HomeController : Controller
  {
    // 省略

    /// <summary>時間をかけてファイルをダウンロードします。</summary>
    public async Task<IActionResult> Download()
    {
      // ダウンロード開始と完了を明確にする目的で待機を入れる
      await Task.Delay(5000);

      // 適当にファイルを作って返す
      var fileSize = 10_000_000;
      var sb = new System.Text.StringBuilder(fileSize);
      for (int i = 0; i < fileSize; i++) sb.Append('a');
      using var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(sb.ToString()));
      return File(stream.ToArray(), "text/plain", $"ダウンロード.txt");
    }
  }
}

클라이언트 처리

일반적으로 웹 브라우저에서 지정된 URL에 액세스하여 파일을 다운로드합니다. 다운로드가 완료된 후 작업을 수행하려는 경우 Javascript로 다운로드를 실행할 수 있습니다.

이를 수행하는 방법에는 여러 가지가 있지만 이 경우 비동기 처리의 원점이기도 XMLHttpRequest 한 를 사용합니다. jQuery ajax 함수 또는 Fetch API를 사용할 수도 있습니다.

ahref 다운로드 URL은 태그에 기록되며 iddownload 설정된 URL을 클릭하면 프로세스가 실행됩니다.

$('#download').click(function (e) {
  console.log('ダウンロードを開始します。');
  e.preventDefault();  // href による画面遷移を抑止
  let url = $(e.target).attr('href');  // href からダウンロード URL 取得

  const xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);   // ダウンロード先 URL 設定
  xhr.responseType = 'blob';   // バイナリデータ取得であることを指示

  // ダウンロード完了後の処理を設定。この時点ではデータは取得してクライアントにありますが保存はしていません。
  xhr.onload = function (oEvent) {
    if (xhr.status !== 200) {
      console.log(`データの取得に失敗しました。(status=${xhr.status})`);
    } else {
      // 取得したデータ
      let blob = xhr.response;

      // レスポンスヘッダーからサーバーから送られてきたファイル名を取得する
      let fileName = '';
      let disposition = xhr.getResponseHeader('Content-Disposition');
      if (disposition && disposition.indexOf('attachment') !== -1) {
        let filenameRegex = /filename[^;=\n]=((['"]).*?\2|[^;\n]*)/;
        let matches = filenameRegex.exec(disposition);
        if (matches != null && matches[1]) {
          // 「filename*=UTF-8''%E3%83%87%E3%83%BC%E3%82%BF.txt;」からファイル名を取得
          fileName = decodeURI(matches[1].replace(/['"]/g, '').replace('utf-8', '').replace('UTF-8', ''));
        }
      }
      if (fileName === '') {
        // ファイル名を取得できなかったら念のため URL をファイル名とする
        let fileName = url.match('.+/(.+?)([\?#;].*)?$')[1];
      }

      // Blob オブジェクトを指す URL オブジェクトを作る
      let objectURL = window.URL.createObjectURL(blob);
      // リンク(<a>要素)を生成し、JavaScript からクリックする
      let link = document.createElement('a');
      document.body.appendChild(link);
      link.href = objectURL;
      link.download = fileName;   // download を指定するとブラウザで開くことなくダウンロードになる
      link.click();
      document.body.removeChild(link);

      console.log('ダウンロードを完了しました。');
    }
  };

  // リクエスト開始
  xhr.send();
});

a 일반적으로 요소를 클릭한 상태로 두면 기본 다운로드 프로세스가 이동하므로 e.preventDefault(); 기본 프로세스를 비활성화하기 위해 호출합니다.

href 에서 다운로드 URL을 가져 와서 XMLHttpRequest GET 에서 가져 오도록 설정하십시오.

XMLHttpRequest.responseTypeblob 이진 데이터를 다운로드하도록 지시합니다.

XMLHttpRequest.onload 데이터 다운로드가 완료된 후의 과정을 이벤트에서 설명할 수 있으므로, 다운로드가 완료된 후의 과정을 여기에 기재한다. 데이터가 클라이언트에만 다운로드되었기 때문에 파일이 실제로 로컬에 저장되지 않습니다. 파일을 로컬에 저장하려면 의사 데이터가 포함된 태그를 a 추가하고 링크를 클릭하고 파일을 저장한 것처럼 동작하도록 할 수 있습니다. 그 당시의 데이터는 함수에 의해 URL로 변환 될 수 window.URL.createObjectURL 있으므로 href 설정하고 작동시킬 수 있습니다.

저장할 파일 이름이 서버의 응답 Content-Disposition 에 포함된 경우 응답 헤더에서 검색할 수 있습니다. 취득하는 것이 조금 복잡하기 때문에 코드는 그대로 사용하는 것이 좋다고 생각합니다. 서버에 파일 이름이 지정되어 있지 않으면 어쩔 수 없기 때문에 기본 파일 이름 또는 URL 경로 끝의 파일 이름으로 설정된다고 생각합니다.

이번에는 파일을 저장 한 후 콘솔에 표시 만 표시하기 때문에이 부분을 임의의 코드로 다시 작성하면 원하는 작업을 수행 할 수 있다고 생각합니다.

데이터 다운로드 프로세스가 설명되면 마지막으로 할 일은 실제로 요청을 시작하는 함수를 호출하는 것입니다 XMLHttpRequest.send .

실행 링크 다운로드

Mr./Ms. Code는 파일을 직접 다운로드하는 패턴과 Javascript로 파일을 다운로드하는 패턴에 대한 링크를 제공합니다. a 태그에 href URL을 직접 쓸 수도 있지만, ASP.NET Core에서 다음을 작성하면 URL이 자동으로 href 로 확장됩니다.

Razor 페이지: Pages/Index.cshtml

<ul>
  <li><a asp-page-handler="Download">ダウンロード (Javascript なし)</a></li>
  <li><a asp-page-handler="Download" id="download">ダウンロード (Javascript あり)</a></li>
</ul>

MVC : 뷰 / 홈 / Index.cshtml

<ul>
  <li><a asp-controller="Home" asp-action="Download">ダウンロード (Javascript なし)</a></li>
  <li><a asp-controller="Home" asp-action="Download" id="download">ダウンロード (Javascript あり)</a></li>
</ul>