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
a
href
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 ดาวน์โหลดจากและXMLHttpRequest
GET
ตั้งค่าให้รับจาก
XMLHttpRequest.responseType
blob
เพื่อสั่งให้ดาวน์โหลดข้อมูลไบนารี
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>