【file-saver】Reactでサーバーを介さずS3のオブジェクトをダウンロードしてみた

React
  • URLをコピーしました!

こんにちは!RYOTAです!

当記事をご覧くださりありがとうございます!

タイトル通りになりますがサーバーを介さずReactコンポーネントでオブジェクトダウンロードの実装を行ったので備忘録としてまとめます。

目次

はじめに

下記が今回の目的と背景になります。

なるべく簡単な方法で実装しようとした結果、今回の実装方法に辿り着きました。

今度も同様のケースがあるかもと思ったのでやったことを簡単に解説していこうと思います。

目的

  • 対象: AWS S3にアップロード済みのオブジェクト(JSONやPNGなど)
  • 環境: ブラウザ上でダウンロード処理を行いローカルに保存する

背景

  • わざわざサーバーを介すのが面倒!以上!

実装

さっそくやっていきましょう。

一番楽な方法から試してみましたが、最終的に一番下の方法で今回は実装が出来ました。

それぞれ起こったことを簡単に解説していきます。

パターン1: aタグのdownload属性を付与

まずはこの一番シンプルな例。

aタグ内にdownload属性を持たせて、リンク先のソースをダウンロードするもの。

これは結論、ダメです。

<a href="s3://hoge.json" download >ダウンロード</a>

これはどうやら同一オリジンのリソースじゃないと無効になってしまうようです。

実際にクリックしてみるとjsonにアクセスしてページ遷移するだけで終わってしまいます。

パターン2: file-saver

お次はライブラリの「file-saver」を使ってみたパターン。

https://www.npmjs.com/package/file-saver

インストール

$ yarn add file-saver
$ yarn add --dev @types/file-saver

実装

import { saveAs } from 'file-saver'

// ~~~~~~~~~~~~~~~~~~~~~~~~~
// ダウンロード
const handleClickDownload = () => {
 const fileName = 'hoge.json'
 const path = `s3://fuga/${fileName}`
    
 saveAs(path, fileName)
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~
<button onClick={handleClickDownload}>ダウンロード</button>

結果

これもダメ。別タブでJSONが開くもののダウンロードが出来ないです。

ログを見てみるとこんなエラーが

Access to fetch at 'hogehoge' from origin 'localhost:fuga' 
has been blocked by CORS policy: 
No 'Access-Control-Allow-Origin' header is present on the requested resource. 
If an opaque response serves your needs, 
set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

CORSのエラーですね。なるほど。なるほど。

パターン3: file-saver + fecth

美しくないけど最終手段。

fetchでオブジェクトを呼んだ後にfile-saverに渡してダウンロードしてあげる方法。

// ダウンロード
const handleClickDownload = async () => {
  const fileName = 'hoge.json'
  const path = `s3://fuga/${fileName}`

  const response = await fetch(path)
  const blob = await response.blob()
  
  saveAs(blob, fileName)
}

最終的にこれで問題なく動きました。

OK!!ダウンロード完了!!

さいごに

色々試してみましたがfetchとfile-saverを使うことでReactでのダウンロード機能が実装できました。

同一オリジンだとサクッとできるっぽいですが、クロスオリジンの時は一工夫必要なようですね。

以上。簡単な解説でした!

最後までご覧いただきありがとうございます!

React

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次