やりたいこと
クライアントからの要求でPDFを作成し、ダウンロードさせる。
完成形はこちら
https://codesandbox.io/s/nuxtdownloadsample-t5itl?fontsize=14
構成
ダウンロードボタンを押すとaxios.get
でapiに問い合わせる。
response.dataでpdfを受け取り、aタグのリンククリックを偽装する。
methods: {
download() {
axios
.get("/api/pdf/test", {
responseType: "blob"
})
.then(response => {
const blob = new Blob([response.data], { type: "application/pdf" });
const url = (window.URL || window.webkitURL).createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "test.pdf";
// aタグ要素を画面に一時的に追加する
document.body.appendChild(a);
a.click();
// 不要になったら削除.
document.body.removeChild(a);
});
}
}
api側は、pdfkitでpdfを生成してresに流し込む。
router.get("/test", (req, res, next) => {
res.setHeader("Content-disposition", "attachment; filename=" + "test.pdf");
res.setHeader("Content-type", "application/pdf");
let doc = new PDFDocument();
doc.pipe(res);
samplePdf(doc);
});
困ったこと
ダウンロードされたpdfの中身が真っ白になった。
具体的には、
- 文字や図形を埋め込んでも表示されない
- 改ページを埋め込むと正しくされている
- 文字にurlリンクを埋め込むと文字は表示されないがリンクの下線は表示され、クリックが動作する
試したこと
-
api側でファイルを保存してみる
→ 正しくpdfができている -
response.dataの中身を見る
→ 「%PDF-1.3」から始まるデータなので正しそう -
<a>
タグを追加してhrefで呼び出す。
→ うまくいく
→ でも先にファイルを作っておくのは要件に合わないしアクセス制御も面倒...
原因
getのオプションにresponseType="blob"
を指定する必要があるらしい。
methods: {
download() {
axios
.get("/api/pdf/test", {
responseType: "blob" // ☆これがポイント
})
axiosのコンフィグを上から見てそれっぽいのを試してたら突然できた。
Qiitaに書こうとしてたら見つけた記事→https://qiita.com/Ryoma0413/items/bc1b75e5e3736ac1fef5
まとめ
公式ドキュメント重要!