用於在下載檔後執行處理的 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>