CSV エクスポート、レポートの PDF ダウンロード、Canvas の画像保存など、JavaScript でファイルをダウンロードさせる機能は多くの Web アプリで必要になります。この記事では a タグの download 属性による基本から、Blob URL を使った動的ファイル生成、fetch でサーバーのファイルを取得してダウンロードする方法まで解説します。
この記事でわかること
・a タグの download 属性による基本的なダウンロード
・Blob URL で動的生成データをダウンロードする方法
・CSV / JSON / テキストファイルの生成とダウンロード
・fetch + Blob でサーバー上のファイルをダウンロード
・ファイル名の指定方法
・クロスオリジン(CORS)の制限と対策
・URL.revokeObjectURL によるメモリ解放
・ダウンロードボタンの実務パターン
・a タグの download 属性による基本的なダウンロード
・Blob URL で動的生成データをダウンロードする方法
・CSV / JSON / テキストファイルの生成とダウンロード
・fetch + Blob でサーバー上のファイルをダウンロード
・ファイル名の指定方法
・クロスオリジン(CORS)の制限と対策
・URL.revokeObjectURL によるメモリ解放
・ダウンロードボタンの実務パターン
ダウンロード方法の比較
| 方法 | データソース | ファイル名指定 | CORS |
|---|---|---|---|
| a タグ + download 属性 | 同一オリジンの URL | ○ | 同一オリジンのみ |
| Blob URL | JavaScript で生成したデータ | ○ | 不要(クライアントで生成) |
| fetch + Blob | サーバー上のファイル | ○ | サーバー側で許可が必要 |
a タグの download 属性でダウンロードする(基本)
HTML の a タグに download 属性を付けるだけで、リンクをクリックしたときにファイルがダウンロードされます。
HTML
<!-- download 属性でファイル名を指定 --> <a href="/files/report.pdf" download="レポート.pdf">PDFをダウンロード</a> <!-- download 属性のみ(ファイル名はサーバーのファイル名) --> <a href="/files/data.csv" download>CSVをダウンロード</a>
JavaScript でボタンクリック時にダウンロードする
JavaScript
function downloadFromUrl(url, filename) {
const a = document.createElement("a");
a.href = url;
a.download = filename || "";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
// 使用例
document.getElementById("downloadBtn").addEventListener("click", () => {
downloadFromUrl("/files/report.pdf", "レポート.pdf");
});
download 属性は同一オリジンの URL でのみ有効です。クロスオリジン(別ドメイン)の URL では download 属性が無視され、ブラウザの通常のナビゲーション(ページ遷移や新しいタブで開く)が行われます。Blob URL で動的生成データをダウンロードする
JavaScript で生成したデータ(テキスト・CSV・JSON など)をダウンロードするには、Blob を作成して URL.createObjectURL() で一時的な URL を生成します。
テキストファイルを生成してダウンロード
function downloadText(text, filename) {
const blob = new Blob([text], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
// メモリ解放
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
// 使用例
downloadText("Hello, World!", "hello.txt");
URL.revokeObjectURL(url) を呼んで Blob URL を解放してください。解放しないと Blob のメモリが保持され続けます。CSV ファイルを生成してダウンロードする
JavaScript
function downloadCSV(data, filename = "data.csv") {
// ヘッダー行
const headers = Object.keys(data[0]);
const csvRows = [
headers.join(","),
...data.map(row =>
headers.map(h => {
const val = String(row[h] ?? "");
// カンマや改行を含む場合はダブルクォートで囲む
return val.includes(",") || val.includes("\n")
? `"${val.replace(/"/g, '""')}"`
: val;
}).join(",")
)
];
// BOM 付き UTF-8(Excel で文字化けしない)
const bom = "\uFEFF";
const blob = new Blob([bom + csvRows.join("\n")], { type: "text/csv" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
}
// 使用例
const users = [
{ name: "田中", age: 30, city: "東京" },
{ name: "鈴木", age: 25, city: "大阪" },
{ name: "佐藤", age: 35, city: "名古屋" }
];
downloadCSV(users, "ユーザー一覧.csv");
CSV を Excel で開くと日本語が文字化けすることがあります。先頭に
BOM(\uFEFF) を付けることで Excel が UTF-8 として正しく認識します。JSON ファイルを生成してダウンロードする
JavaScript
function downloadJSON(data, filename = "data.json") {
const json = JSON.stringify(data, null, 2);
const blob = new Blob([json], { type: "application/json" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
}
// 使用例
downloadJSON({ name: "田中", age: 30 }, "user.json");
fetch + Blob でサーバー上のファイルをダウンロードする
サーバー上のファイルを JavaScript 経由でダウンロードしたい場合(ファイル名を動的に変更したい、認証ヘッダーを付けたい場合など)は、fetch で取得して Blob に変換します。
JavaScript
async function downloadFile(url, filename) {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const blob = await res.blob();
const blobUrl = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = blobUrl;
a.download = filename;
a.click();
URL.revokeObjectURL(blobUrl);
}
// 使用例: APIから認証付きでファイルを取得
async function downloadReport() {
const res = await fetch("/api/report", {
headers: { Authorization: "Bearer " + token }
});
const blob = await res.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "report.pdf";
a.click();
URL.revokeObjectURL(url);
}
fetch を使えば認証ヘッダー(Bearer トークンなど)を付けてファイルを取得できます。a タグの download 属性だけでは認証が必要なファイルはダウンロードできません。
クロスオリジン(CORS)の制限と対策
| 状況 | download 属性 | fetch + Blob |
|---|---|---|
| 同一オリジン | ○ 有効 | ○ 動作する |
| クロスオリジン(CORS 許可あり) | × 無視される | ○ 動作する |
| クロスオリジン(CORS 許可なし) | × 無視される | × エラー |
別ドメインのファイルをダウンロードしたい場合は、fetch + Blob を使い、サーバー側で Access-Control-Allow-Origin ヘッダーを設定してもらう必要があります。
クロスオリジンの制限はブラウザのセキュリティ機能です。CORS ヘッダーの設定はサーバー側の管理者に依頼してください。
汎用ダウンロード関数
Blob URL 生成・a タグ作成・クリック・メモリ解放を共通化した汎用関数です。
JavaScript
function download(blob, filename) {
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
// テキスト
download(new Blob(["Hello"], { type: "text/plain" }), "hello.txt");
// CSV
download(new Blob(["\uFEFFname,age\n田中,30"], { type: "text/csv" }), "data.csv");
// JSON
download(new Blob([JSON.stringify(data)], { type: "application/json" }), "data.json");
実務でよく使うパターン
Canvas の画像をダウンロードする
JavaScript
const canvas = document.getElementById("myCanvas");
document.getElementById("saveBtn").addEventListener("click", () => {
canvas.toBlob(blob => {
download(blob, "drawing.png");
}, "image/png");
});
テーブルデータを CSV エクスポートする
JavaScript
function exportTableToCSV(tableId, filename = "table.csv") {
const table = document.getElementById(tableId);
const rows = [...table.querySelectorAll("tr")];
const csv = rows.map(row =>
[...row.querySelectorAll("th, td")]
.map(cell => `"${cell.textContent.replace(/"/g, '""')}")`)
.join(",")
).join("\n");
download(
new Blob(["\uFEFF" + csv], { type: "text/csv" }),
filename
);
}
document.getElementById("exportBtn").addEventListener("click", () => {
exportTableToCSV("dataTable", "エクスポート.csv");
});
ダウンロードボタンにローディング表示を付ける
JavaScript
const btn = document.getElementById("downloadBtn");
btn.addEventListener("click", async () => {
btn.disabled = true;
btn.textContent = "ダウンロード中...";
try {
const res = await fetch("/api/export");
const blob = await res.blob();
download(blob, "export.xlsx");
} catch (err) {
alert("ダウンロードに失敗しました");
} finally {
btn.disabled = false;
btn.textContent = "ダウンロード";
}
});
関連記事
- クリップボードにコピーする方法 — Clipboard API
- クリックイベントの設定方法
- 送信ボタンの二重クリック防止
- HTML 要素を追加・削除する方法
- getAttribute の使い方
よくある質問
Qdownload 属性が効きません。ファイル名が指定されずにブラウザで開いてしまいます。
A
download 属性は同一オリジンの URL でのみ有効です。別ドメインの URL では無視されます。クロスオリジンのファイルをダウンロードするには fetch + Blob を使ってください。QCSV をダウンロードすると Excel で文字化けします。
ACSV の先頭に
BOM(\uFEFF) を付けてください。new Blob(["\uFEFF" + csv], { type: "text/csv" }) とすることで、Excel が UTF-8 として正しく認識します。QURL.revokeObjectURL を呼ばないとどうなりますか?
ABlob URL が解放されず、Blob のメモリが保持され続けます。小さなファイルなら問題になりませんが、大きなファイルや繰り返しダウンロードする場面ではメモリリークの原因になります。ダウンロード後に必ず呼んでください。
Qfetch で認証が必要なファイルをダウンロードするには?
Afetch の
headers オプションに認証情報(Bearer トークンなど)を渡します。レスポンスを res.blob() で Blob に変換し、URL.createObjectURL でダウンロードします。QCanvas の描画内容をダウンロードするには?
A
canvas.toBlob(blob => { ... }) で Blob を取得し、URL.createObjectURL で a タグにセットしてダウンロードします。PNG なら "image/png"、JPEG なら "image/jpeg" を指定します。まとめ
JavaScript でファイルをダウンロードする方法を整理しました。
- 同一オリジンの URL: a タグ +
download属性(最もシンプル) - 動的生成データ:
Blob+URL.createObjectURL(CSV / JSON / テキスト) - サーバー上のファイル:
fetch + res.blob()(認証付き・CORS 対応) - メモリ解放:
URL.revokeObjectURLを忘れずに - Excel 文字化け対策: CSV の先頭に BOM(\uFEFF)を付ける
CSV エクスポートや Canvas 画像の保存は実務で頻出するパターンです。汎用の download 関数を用意しておくと、さまざまな場面で再利用できます。