ファイルのダウンロードがどのように処理されるかを指定することは、すべてContent-disposition
ヘッダーに帰着します。ここでもファイル名を指定できます。また、Content-type
指定されたファイルの処理方法をブラウザが確実に認識できるように を設定します。
Express.js の例:
app.post('/url/to/hit', function(req, res, next) {
var stream = fs.readStream('/location/of/pdf');
var filename = "WhateverFilenameYouWant.pdf";
// Be careful of special characters
filename = encodeURIComponent(filename);
// Ideally this should strip them
res.setHeader('Content-disposition', 'inline; filename="' + filename + '"');
res.setHeader('Content-type', 'application/pdf');
stream.pipe(res);
});
をよく見てみると、Content-disposition
このinline;
フィールドが、ブラウザがファイルにどのように反応するかを設定するものであることがわかります。ダウンロードを強制したい場合は、次のように設定inline;
してください。attachment;
ファイル名に特殊文字を設定すると、ファイルが壊れる可能性があることもわかりました(数回焼いたことで)。だから私encodeURIComponent()
はそれが起こらないことを保証するファイル名です。
他の人が同じことを理解しようとしているのに役立つことを願っています!
編集
これを最初に投稿してから現在までの間に、content-disposition
のファイル名パラメーターを正しくエンコードする方法を見つけました。 仕様によると、ファイル名は RFC5987 でエンコードされている必要があります。 ここでエンコーディングを正しく処理する MDNのサンプル コード スニペット を見つけることになりました (encodeURIComponent()
このフィールドの完全に正しい形式ではありません)。
MDN スニペット
var fileName = 'my file(2).txt';
var header = "Content-Disposition: attachment; filename*=UTF-8''"
+ encodeRFC5987ValueChars(fileName);
console.log(header);
// logs "Content-Disposition: attachment; filename*=UTF-8''my%20file%282%29.txt"
function encodeRFC5987ValueChars (str) {
return encodeURIComponent(str).
// Note that although RFC3986 reserves "!", RFC5987 does not,
// so we do not need to escape it
replace(/['()]/g, escape). // i.e., %27 %28 %29
replace(/\*/g, '%2A').
// The following are not required for percent-encoding per RFC5987,
// so we can allow for a little better readability over the wire: |`^
replace(/%(?:7C|60|5E)/g, unescape);
}
これに加えて、ブラウザも仕様に完全には準拠していません。一部のキャラクターは、ダウンロードから正しく返されません (少なくとも私がテストしたとき)。
ダウンロードの仕組みを更新することで、この問題を回避できます。ダウンロード URL がファイル名で終わる場合 (ヘッダーに属性を指定しないfilename
場合)、URL エンコードされた値からファイル名を正しく取得します。IE'http://subdomain.domain-url.com/some/path/to/downloads/' + encodeURIComponent("You're there, download this!.pdf")
ダウンロードにファイル名を指定するためです。