フロント側はReact、サーバーサイドはRailsでファイルダウンロードが
うまくいかないケースがあり、それを解消した記事内容になります。
症状としては、axiosのissueにあったこのケースに当たります。
Github | axios/axios | Empty response when responseType is blob or arraybuffer.
サーバーサイドとフロント部分の結合部分なので、
原因の特的ができていなくて引っかかってる人が多そうですね。
私のケースの場合は、railsでheadの記述が不要だったのですが、
それだけじゃよくわからないと思います。
実装をみながら解消方法をみていきましょう。
フロント側の記述
フロント側は以下のようなコードにしています。
$ yarn add file-saver
import { saveAs } from 'file-saver';
~~
export const fileDownload = () {
axios
.get(url, {
~~,
responseType: 'blob',
})
.then((response) => {
const blob = new Blob([response.data], {
type: response.data.type,
});
saveAs(blob, downoloadFileName);
});
}
(ちなみにaタグにdownload属性をつけるやり方もあります。)
これでフロント側はOKです。
ただ、空ファイルをダウンロードしてしまう場合があります。
const blobの上でブレイクポイントで止めて見ると、以下のような感じです。
Blobのサイズが0になっていたり、画像やpdfをダウンロードしようとしているのですが、typeがtext/xmlになっています。
こんなときはサーバーサイド側に問題があります。
サーバーサイド側の記述
私の触ったコードのケースではrailsでsend_data()を使ってfileの実体を送っていました。
記述は以下のような感じにもともとなっていました。
def download
upload_file = UploadFile.find(file_params)
file = upload_file.file.blob.download # モデルでhas_one_attached :fileを記述
if send_data(file, disposition: 'attachment',
filename: upload_file.file.blob.filename.to_s,
~~
~~
head :no_content # これがあるとうまくいかない。
else
~~
end
end
send_data()の引数自体は問題ないのですが、このコードはうまくいきませんでした。
head :no_contentが不要でした。
head :no_contentを削除すると、フロント側のレスポンスが以下のように変わります。
Blobのsizeやtypeにちゃんと値が入ります。
ダウンロードした画像も表示できました。