用于在下载文件后执行处理的 Javascript

更新页 :
页面创建日期 :

操作验证环境

Visual 工作室
  • Visual Studio 2022
ASP.NET 核心
  • 8.0 (Razpr Pages, MVC)
Web 浏览器
  • 边缘 119

操作环境

Visual Studio(如果还包括服务器程序)
  • Visual Studio 2022
ASP.NET Core(如果还包括服务器程序)
  • 8.0 (Razpr Pages, MVC)
Web 浏览器
  • 边缘
  • 谷歌浏览器
  • 其他浏览器(未全部选中)

(* 这个技巧的主体是客户端进程,所以服务器端可以是任何东西)

起先

这些提示的主要重点是客户端程序(Javascript),而服务器程序仅用于下载文件。 因此,服务器程序是什么并不重要,只要它能让你下载文件就行。

让用户在服务器上访问文件时下载文件

Mr./Ms. 允许您在收到请求时下载文件。 这时,我们特意在服务器上等待一定的时间,以便于理解下载的开始和结束。

下面是 Razor Pages 和 MVC 服务器端发生的情况: 可以在其他项目(如 Web API)中实现它。

Razor 页数:页数/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");
    }
  }
}

客户端处理

通常,您可以通过访问 Web 浏览器中的指定 URL 来下载文件。 如果要在下载完成后执行某些操作,可以使用 Javascript 运行下载。

有很多方法可以做到这一点,但在这种情况下,我们将使用 ,这也是 XMLHttpRequest 异步处理的起源。 您还可以使用 jQuery ajax 函数或 Fetch API。

ahref下载 URL 写入标签id中,并在单击设置为download的 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,并将其XMLHttpRequestGET设置为从中获取。

XMLHttpRequest.responseTypeblob以指示要下载的二进制数据。

XMLHttpRequest.onload 由于数据下载完成后的过程可以在事件中描述,因此这里写入下载完成后的过程。 由于数据仅下载到客户端,因此文件实际上并未存储在本地。 要在本地保存文件,您可以添加包含伪数据的 a 标记,并使其行为就像单击链接并保存文件一样。 该函数可以将当时 window.URL.createObjectURL 的数据转换为 URL,因此 href 您可以将其设置为并使其工作。

如果要保存的文件名包含在服务器 Content-Disposition 的响应中,则可以从响应标头中检索该文件名。 由于获取起来有点复杂,我认为代码应该按原样使用。 如果服务器上没有指定文件名,则无济于事,因此我认为会将其设置为默认文件名或URL路径末尾的文件名。

由于这次我只在保存文件后才在控制台中显示它,我认为可以通过用任意代码重写这部分来执行所需的操作。

描述数据下载过程后,我们要做的最后一件事就是 XMLHttpRequest.send 调用函数来实际启动请求。

下载运行链接

Mr./Ms. Code 提供了直接下载文件的模式和使用 Javascript 下载文件的模式的链接。 a 您可以直接在标记中 href 写入 URL,但如果在 ASP.NET Core 中写入以下内容,则 URL 将自动 href 展开为 。

Razor Pages: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:Views/Home/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>