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

หน้ามีดโกน : หน้า/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 : โคลโทลเลอร์/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 ที่ระบุในเว็บเบราว์เซอร์ หากคุณต้องการทําอะไรบางอย่างหลังจากการดาวน์โหลดเสร็จสิ้นคุณสามารถเรียกใช้การดาวน์โหลดด้วย

มีหลายวิธีในการทําเช่นนี้ แต่ในกรณีนี้เราจะใช้ ซึ่งเป็น XMLHttpRequest ที่มาของการประมวลผลแบบอะซิงโครนัส คุณยังสามารถใช้ฟังก์ชัน jQuery ajax หรือ Fetch API

ahref URL ดาวน์โหลดถูกเขียนในแท็กและidกระบวนการจะดําเนินการเมื่อคลิกหนึ่งชุดเป็นdownload

$('#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คุณสามารถเขียน URL ลงในแท็กได้โดยตรง href แต่ถ้าคุณเขียนสิ่งต่อไปนี้ใน ASP.NET Core URL จะขยายเป็น . โดยอัตโนมัติhref

หน้ามีดโกน : 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>