Javascript to perform processing after downloading a file
Operation verification environment
- Visual Studio
-
- Visual Studio 2022
- ASP.NET Core
-
- 8.0 (Razpr Pages, MVC)
- Web Browsers
-
- Edge 119
Operating environment
- Visual Studio (if you also include server programs)
-
- Visual Studio 2022
- ASP.NET Core (if it also includes server programs)
-
- 8.0 (Razpr Pages, MVC)
- Web Browsers
-
- Edge
- Google Chrome
- Other browsers (not all checked)
(* The main body of this tip is the client-side process, so the server side can be anything)
At first
The main focus of these tips is the client program (Javascript), and the server program is only there to download files. Therefore, it does not matter what the server program is, as long as it can make you download the file.
Have users download files when they are accessed on the server
Mr./Ms. allows you to download files when you receive a request. At that time, we deliberately wait for a certain amount of time on the server so that it is easy to understand the start and end of the download.
Here's what happens on the server side of Razor Pages and MVC: You can implement it in other projects, such as Web API.
Razor Pages : 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");
}
}
}
Client processing
Normally, you download a file by accessing a specified URL in a web browser. If you want to do something after the download is complete, you can run the download with Javascript.
There are many ways to do this, but in this case, we will use , which is also XMLHttpRequest
the origin of asynchronous processing.
You can also use jQuery ajax functions or the Fetch API.
a
href
The download URL is written in the tag and id
the process is executed when the one set to download
is clicked.
$('#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
Normally, if you leave the element clicked, the default download process will move, so e.preventDefault();
we call to disable the default process.
href
Get the download URL from and XMLHttpRequest
GET
set it to get it from .
XMLHttpRequest.responseType
blob
to instruct the binary data to be downloaded.
XMLHttpRequest.onload
Since the process after the data download is completed can be described in the event, the process after the download is completed is written here.
Since the data has only been downloaded to the client, the file is not actually stored locally.
To save a file locally, you can add a tag that a
contains pseudo-data and make it behave as if you had clicked on a link and saved the file.
The data at that time can window.URL.createObjectURL
be converted to a URL by the function, so href
you can set it to and make it work.
The file name to be saved can be retrieved from the response header if it is included in the response from the Content-Disposition
server.
Since it is a little complicated to acquire, I think that the code should be used as it is.
If the file name is not specified on the server, it cannot be helped, so I think that it will be set to the default file name or the file name at the end of the URL path.
Since this time I only display it in the console after saving the file, I think that the desired operation can be executed by rewriting this part with arbitrary code.
Once the data download process is described, the last thing we want to do is XMLHttpRequest.send
call a function to actually start the request.
Download run link
Mr./Ms. Code provides links to the pattern of downloading the file directly and the pattern of downloading it with Javascript.
a
You can write the URL directly in the href
tag, but if you write the following in ASP.NET Core, the URL will automatically href
expand to .
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>