ReactでS3へのマルチアップロードを実装する (動画サイト構築までの道③)
はじめに
ここまで 3 本記事でしばらく連載してきました「動画サイト構築までの道」最後となります
本日は React と AWS SDK を使って動画ファイルをアップロードする仕組みを作成していきます。動画ファイルはサイズが大きいことが予想されるのでマルチパートアップロードを利用していきます。
ここまで内容を利用すれば React を利用した動画サイトが作成できるかと思います
過去のシリーズ
環境
VSCode
Ubuntu 20.04 (WSL2)
Docker 20.10.12
docker-compose version v2.2.3
git version 2.25.1
前準備
今回はこのような画面を作成します
この画面ですが以下の動画を参考に作らせていただきました。プログラミングチュートリアルさんいつも本当にお世話になっております
また今回は動画とは少し変えてtailwindCSS
とreact-dropzone
を利用しています
今回のハンズオンに必要なライブラリをインストールします
以下のリポジトリをクローンして行っていきます
$ git clone https://github.com/jinwatanabe/streaming_aws_handson
$ cd streaming_aws_handson/chapter1
$ yarn
まずはtailwindCSS
からいれていきます
公式サイト通りに設定していきます
$ yarn add tailwindcss postcss autoprefixer]
$ yarn tailwindcss init -p
次にtailwind.config.js
を以下にします
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{js,jsx,ts,tsx}"],
theme: {
extend: {},
},
plugins: [],
};
次にincex.ccs
を以下にします
@tailwind base;
@tailwind components;
@tailwind utilities;
これで設定完了です。
次にドロップゾーン用のライブラリをインストールします
$ yarn add react-dropzone
AWS SDK
今回は以下の記事と動画を参考に S3 へのアップロードの関数を作成します
AWS SDK とそれに関するライブラリが必要になるためインストールします
$ yarn add @aws-sdk/client-s3 @aws-sdk/lib-storage aws-sdk
S3 の用意
AWS コンソールから「S3」と調べてクリックします
「バケットを作成」をクリック
「バケット」にバケット名をいれます。ここでは「hls-handson」としています。
バケット名はすべてでユニークでないとエラーになるため、ここからは読み替えてハンズオンを進めてください
「バケットを作成」をクリックします」
作成したバケット名をクリックします
ここからはCross-Origin Resource Sharing (CORS)
の設定をしていきます。
今のままでは React から S3 にアクセスすると不正なアクセスとしてエラーになり、アップロードができないのでそこを許可するものだと思って大丈夫です
ここは以下の記事を参考に設定していきます
タブメニューから「アクセス許可」をクリック
「Cross-Origin Resource Sharing (CORS)」から「編集」をクリック
以下のコードを張り付けて「変更の保存」をクリック
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"HEAD",
"GET",
"PUT",
"POST",
"DELETE"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": [
"ETag"
]
}
]
これで S3 の準備ができました
IAM の認証情報
ここからは S3 にアクセスするためのアクセスキーを取得します
既にある方はスキップして大丈夫です
AWS コンソールから「IAM」と検索してクリックします
左メニューから「ユーザー」をクリック
アクセスに使用するユーザーをクリック(S3 のアクセス権限 orAdmin 権限があるもの)
タブメニューから「認証情報」をクリック
「アクセスキー」の「アクセスキー作成」をクリックすると「アクセスキー」と「シークレットアクセス」が取得できるのでメモしておきましょう
今後も利用するのでファイルでダウンロードして保存しておくとよいです
React の実装
実際に動画アップロードフォームを作成します
以下のコードをApp.tsx
にはりつけます
import React, { useCallback, useRef, useState } from "react";
import { useDropzone } from "react-dropzone";
import { Credentials } from "aws-sdk";
import { Upload } from "@aws-sdk/lib-storage";
import { S3Client } from "@aws-sdk/client-s3";
import ImageLogo from "./image.svg";
function App() {
const inputRef = useRef<HTMLInputElement>(null);
const [isLoading, setIsLoading] = useState(false);
const onDrop = useCallback(async (acceptedFiles: File[]) => {
setIsLoading(true);
const file = acceptedFiles[0];
const creds = new Credentials(
"[AWSのアクセスキー]",
"[AWSのシークレットアクセスアクセスキー]"
);
try {
const parallelUploads3 = new Upload({
client: new S3Client({ region: "ap-northeast-1", credentials: creds }),
params: { Bucket: "[バケット名]", Key: file.name, Body: file },
leavePartsOnError: false,
});
parallelUploads3.on("httpUploadProgress", (progress) => {
console.log(progress);
});
await parallelUploads3.done();
await setIsLoading(false);
} catch (e) {
console.log(e);
}
}, []);
const { getRootProps, getInputProps } = useDropzone({
onDrop,
});
const fileUpload = () => {
if (inputRef.current == null) return;
inputRef.current.click();
};
const onFileInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.target.files == null) return;
console.log(event.target.files[0]);
};
return (
<div className="App">
<div className="flex justify-center items-center h-screen">
{isLoading ? (
<h1>アップロード中・・・</h1>
) : (
<div
className="rounded shadow-lg w-1/2"
style={{ maxWidth: "400px", minWidth: "300px" }}
>
<div className="flex justify-center">
<div className="my-8 flex justify-center grid">
<h1 className="font-bold text-gray-500 col-span-3 text-center">
動画アップロード
</h1>
<div className="text-gray-500 col-span-3 text-center mt-2 mb-4 text-xs">
MP4の動画ファイルを選択
</div>
<div
className="border-dashed border-2 border-gray-500 grid flex justify-cente p-4 mb-2 cursor-pointer"
style={{ minWidth: "200px" }}
{...getRootProps()}
>
<input {...getInputProps()} />
<div className="container flex justify-center mb-2">
</div>
<div className="container flex justify-center text-xs text-gray-500">
<p>ここにドラッグ&ドロップしてね</p>
</div>
</div>
<div className="col-span-3 text-center my-1 text-gray-500">
または
</div>
<div className="col-span-3 flex justify-center w-full">
<button
onClick={fileUpload}
className="bg-blue-500 rounded text-white font-bold py-2 px-4 w-full"
>
ファイルを選択
</button>
<input
type="file"
className="hidden"
accept=".mp4"
ref={inputRef}
onChange={onFileInputChange}
/>
</div>
</div>
</div>
</div>
)}
</div>
</div>
);
}
export default App;
React を起動して確認します
$ yarn start
localhost:3000
にアクセスして以下の画面が表示されました
次にアップロードのために以下の部分を各自変更します
今回はドロップゾーンにのみ S3 のアップロード機能をつけています
ボタンからのアップロードにも同じ要領でぜひ追加してみてください
それでは実際に試してみます
今回はtest.mp4
をあげてみます (リポジトリにあります)
ドロップすると以下の画面になります
アップロード中はuseState
であるisLogin
をtrue
にしてアップロード画面に切り替えています。すべてのアップロードが終わるとfalse
に戻して先ほどの画面に戻ります
画面が戻ったら、作成した S3 を開きます。するとファイルがアップロードできていることが確認できます
おわりに
ここまで長いハンズオンお疲れさまでした
3 回にわたって動画サイト構築に必要な AWS のハンズオンを行ってきましたがいかがでしたでしょうか
思ったよりも簡単な技術で裏の仕組みが作成できるので、あとは CMS などを利用してデータ回りの保存ができるようになれば動画サイトは作れるかと思います
ぜひともこの先もチャレンジしてみてください
Discussion