S3にあるはずのPDFファイルがダウンロードできないの、なぁぜなぁぜ?
こんにちは、さわちゃんです。
今日はS3にあるはずのPDFファイルがダウンロードできない(厳密に言うとダウンロードディレクトリに保存されずに直接ブラウザで開かれてしまう)現象について、基礎的なところを見落としていたので共有したいと思います。
環境
Laravel + Inertiaを利用したMPAで、フロントのフレームワークはReactを採用しています。
Laravel v10.5.1
Inertia.js v0.6.9
React v9.5.0
(今回はどのフレームワーク・ライブラリでも起こり得るので↑の事項はあんまり関係ないです)
起きた現象
S3に保存されていたPDFファイルをブラウザでダウンロードする機能があり、フロント側では以下のようなコードを書いてダウンロードする仕組みを実装しました。
<a href={S3にアップされたファイルURL} download={ファイル名}>
ダウンロード!
</a>
いざブラウザでこのリンクを踏んでみると、なぜかダウンロードは行われず、PDFファイルの内容がブラウザ上に表示されてしまうという挙動になりました。
原因
HTTPレスポンスヘッダでした。
S3のURLにアクセスした際のHTTPレスポンスヘッダが
Content-Type: application/pdf
になっていて、ブラウザにPDFだよ!と教えてしまっていました。
ブラウザくん「お、PDFやんけ!ならワシがバシッと中身を表示したる!」
ということで、ダウンロードされずに表示されてしまったんですね。
解決策
HTTPレスポンスヘッダのContent-Typeを以下のように変更しましょう。
Content-Type: binary/octet-stream
そうすることによって「とりあえずこれはファイルですよ!」ってことをブラウザに伝えることができるので、ダウンロードできるようになります。
- S3に直接ファイルをアップしている場合は、S3のファイルのメタデータを直接いじる
- Laravelからファイルアップロードを行う場合は、メタデータを指定した上でアップロードする
などの対応が必要ですね。
S3の設定は以下の箇所から行えます。
アプリ(Laravel)側で行うとしたら以下のように指定できます。
Storage::put($fileName, $contents, [
'mimetype' => 'binary/octet-stream',
]);
逆にPDFをブラウザで表示したいのになぜかダウンロードされてしまう・・・という場合は、
Content-Type: application/pdf
としてあげたらOKです。
以上です。
お疲れ様でした。