24
30

More than 5 years have passed since last update.

JSでZipファイルをダウンロードさせる方法

Last updated at Posted at 2019-01-21

背景

axiosでS3からzipをダウンロードして、それをダウンロードさせる場面があったので、良くある感じでコードを書いてみた。

前提として 

  • S3にはバックエンドから発行されるPresigned URLを使う
  • バックエンドを通さず、そのURLに直接アクセスする

最初に書いたコード

await { data } = axios.get('....')
const blob = new Blob([data], { type: 'application/zip' })

const uri = URL.createObjectURL(blob)
const link = document.createElement('a')
link.download = 'sample.zip'
link.href = uri
link.click()

その結果…

ファイルのダウンロードは成功するけれど、解凍するとZipの中身が壊れている…

怪しいと思い、拡張子を .txt にして開いてみると、バイナリのようなテキストが並んでるので、Zipとして正しく解釈できていない模様。

フロントエンドだけで完結する対策として、この2つを思いついたので、どっちが良いか試してみる

  1. S3 Presigned URL に直接アクセスさせる
  2. ファイルの変換をうまくやる

動作確認

1. S3 Presigned URLに直接アクセスさせる

const link = document.createElement('a')
link.download = 'sample.zip'
link.href = '....'
link.click()

とりあえずダウンロードはできる。けれど、ファイル名が download で指定したものとは違う…

ググった結果ここにたどり着く。

This attribute only works for same-origin URLs.

という訳で、直接S3 Presigned URLにアクセスするとファイル名を制御できない。

セキュリティ考えるとまあそうかなという仕様ですね。

2. ファイルの変換をうまくやる

ArrayBufferを指定して、明示的にバイナリデータを受信するように設定、

const { data } = await axios.get('....', {
  responseType: 'arraybuffer',
  headers: { Accept: 'application/zip' },
})
const blob = new Blob([data], { type: 'application/zip' })

または、直接Blobを指定して構築してもらう。

const { blob: data } = await axios.get('....', {
  responseType: 'blob',
  headers: { Accept: 'application/zip' },
})

これであとは、ファイルへのリンクをクリックさせるだけ!

const uri = URL.createObjectURL(blob)
const link = document.createElement('a')
link.download = 'sample.zip'
link.href = uri
link.click()

これで無事、Zipファイルがダウンロードできました。

Todo

24
30
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
30