Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
RemixとCloudflare Stack におけるFile Upload
Search
Ossamoon
September 25, 2024
Programming
440
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
RemixとCloudflare Stack におけるFile Upload
Ossamoon
September 25, 2024
More Decks by Ossamoon
See All by Ossamoon
楽譜フォント(SMuFL)をCloudflareで配信する
ossamoon
0
150
SSRアプリケーションにおけるPKCE付き認可コードフロー
ossamoon
0
68
Other Decks in Programming
See All in Programming
PHP に部分適用が来るぞ!……ところで何それ?おいしいの? #phpcon / phpcon-2026
shogogg
0
380
ソフトウェア設計に溶けるインフラ ― AWS CDK のインフラ認識論
konokenj
3
660
AI駆動開発を妨げる技術的負債の解消アプローチ / ai-refactoring-approach
minodriven
17
9.4k
関数型プログラミングのメリットって何だろう?
wanko_it
0
200
はてなアカウント基盤 State of the Union
cockscomb
1
1.3k
「正の参照」と 「負の導出」で組む ハーネスエンジニアリング
cottpan
1
150
コーディングルールの鮮度を保ちたい for SRE NEXT 2026 / keep-fresh-go-internal-conventions-sre-next-2026
handlename
0
150
変わらないものが、変わるものを決める — 意図駆動開発 × イベントソーシング × イミュータブル | What Doesn't Change Decides What Can — IDD × Event Sourcing × Immutability
tomohisa
0
480
Go言語とトイモデルで学ぶTransformerの気持ち / fukuokago23-transformer
monochromegane
0
140
琵琶湖の水は止められてもNet--HTTPのリトライは止められない / You might be able to stop the water flow of Lake Biwa but you can't stop Net::HTTP retries
luccafort
PRO
0
450
テーブルをDELETEした
yuzneri
0
110
Laravel Boostに学ぶ、AIにPHPを書かせる技術 〜OSSの実装から蒸留するエージェント制御の王道〜
kentaroutakeda
3
540
Featured
See All Featured
Mobile First: as difficult as doing things right
swwweet
225
10k
Between Models and Reality
mayunak
4
380
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
240
WENDY [Excerpt]
tessaabrams
11
39k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.4k
AI: The stuff that nobody shows you
jnunemaker
PRO
9
840
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
2.9k
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
290
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
5
1.1k
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
660
Rails Girls Zürich Keynote
gr2m
96
14k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2k
Transcript
RemixとCloudflare Stack におけるFile Upload Remix Tokyo Meetup, 2024.09.25
自己紹介 - 齋藤 修(Ossamoon) - Webフロントエンジニア - Reactばかり触っている - フリーランス
- 趣味:音楽 - クラシック音楽が好き
Remixを使ったプロダクトを個人開発中 - クラシック音楽の音源をクラウドにアップロード - 楽譜を表示しながらストリーミング再生 最初の壁として立ちはだかったのが、File Upload
File Uploadに求めること - 認証・認可 - ユーザーを認証したい - アップロード上限を超えていないかをチェックしたい - データベースの更新
- アップロードした音源に関する情報をデータベースに保存したい - アップロードに失敗した場合はデータベースの更新も失敗して欲しい( Atomicity: 原子性) - Cloudflareの制約を満たす - 特にCloudflare Workersは実行時間やメモリの制約が厳しいため、考慮する必要がある
RemixにおけるFile Upload
RemixのFile Uploadに関するAPI - unstable_parseMultipartFormData - unstable_createMemoryUploadHandler - unstable_createFileUploadHandler - Node.jsでのみ動作
- unstable_composeUploadHandlers - APIリファレンスにも載っていない内部的な API すべてmultipart/form-dataを使う想定のAPI 今回は この2つを利用 ← ←
multipart/form-dataとは - HTTPに定義されている仕様 - formに入力したテキストと ファイルのバイナリを 同時に送信できる POST /upload HTTP/1.1
Host: example.com Content-Type: multipart/form-data; boundary=----- Content-Length: 1024 ----- Content-Disposition: form-data; name="field1" value1 ----- Content-Disposition: form-data; name="field2" value2 ----- Content-Disposition: form-data; name="file"; filename="example.jpg" Content-Type: image/jpeg (...ファイルのバイナリデータ...) -----
APIの使い方(action) const uploadHandler = unstable_createMemoryUploadHandler({ maxPartSize: 5 * 1024 *
1024, // これを超えるサイズのファイルは扱えない }); const formData = await unstable_parseMultipartFormData(request, uploadHandler); const title = formData.get("title") as string; const audioFile = formData.get("audiofile") as File; 1. unstable_createMemoryUploadHandler で uploadHandler を作成 2. unstable_parseMultipartFormData で formDataを作成 3. formDataから必要なデータを取得
export async function action({ request, context }: ActionFunctionArgs) { //
認証 const user = await authenticator.isAuthenticated(request); // FormDataを取得 const uploadHandler = unstable_createMemoryUploadHandler({ maxPartSize: 5 * 1024 * 1024, // 5MB }); const formData = await unstable_parseMultipartFormData( request, uploadHandler ); const title = String(formData.get("title")); const audioFile = formData.get("audiofile") as File; // R2にファイルをアップロード const { R2 } = context.cloudflare.env; const object_key = crypto.randomUUID(); const upload_info = await R2.put(object_key, await audioFile.arrayBuffer(), { httpMetadata: { contentType: audioFile.type, }, }); // TrackをDBに追加 const track = await db.track.create(object_key, title, user.id); redirect("tracks"); } 認証とDB更新 も含めた コードの全体像
APIの使い方(component) 1. <Form>のencTypeにmultipart/form-dataを指定 2. あとは普通のformと同様に書く <Form method="post" encType="multipart/form-data"> <label htmlFor="title">タイトル</label>
<input id="title" type="text" name="title" /> <label htmlFor="audiofile">音源ファイル</label> <input id="audiofile" accept="audio/*" type="file" name="audiofile" /> <button type="submit">送信</button> </Form>
multipart/form-dataのメリット・デメリット 👍 実装がシンプル 👍 認証・認可をaction内で処理できる 👍 DB更新も同じaction内で記述することができ る 👎 Workerの実行時間・使用メモリがファイルサ
イズに大きく依存する 👎 Multipart uploadやprogressの表示といった ユーザー体験の最適化が実現しにくい FileUploadのもう一つの実装方法である 署名付きURLも検討したい
署名付きURL
署名付きURLとは - 特定の操作(今回の場合はファイルのアップロード)を認可する署名を追加した URL - Cloudflare R2はS3互換であるため、署名付きURLを用いることができる - Workerで署名付きURLを発行し、クライアントからR2に直接ファイルをアップロード する
- 有効期限を適切に定める必要がある
署名付きURLの流れ 1. クライアントがWorkerに署名付き URLをリクエスト 2. Workerが認証 3. Workerがデータベースに新しいレ コードを作成 4.
Workerが署名付きURLを返す 5. クライアントが署名付きURLを用 いてR2にファイルをアップロード 6. クライアントがWorkerにアップ ロード完了を伝える 7. Workerがデータベースに追加し たレコードを更新 8. (定期実行) ファイルアップロード に失敗した分のデータを削除
署名付きURLのメリット・デメリット 👍 Workerの実行時間・使用メモリがファイル サイズに依存しない 👍 Multipart uploadやprogressの表示といった ユーザー体験の最適化が実現しやすい 👎 有効期限内の署名付き
URLを知れば誰でも アップロードができるので、認証・認可が完 全ではない 👎 Atomicityを保つために実装が複雑になって しまう
さらなるユーザー体験の向上へ - Multipart upload - ファイルをいくつかの partに分割してアップロードする - 並列化による最適化や、ネットワーク切断からの回復に貢献する -
大容量(だいたい100MB以上)のファイルアップロードによく使われる - Progressの表示 - ファイルの何%がアップロードできたかを表示したい - fetchのbodyにReadbleStreamを指定することで、経過を観察することができる - 上記機能はChromeでのみ利用可能 - 他のブラウザもサポートしたい場合、 XMLHttpRequestやaxiosを利用する必要がある これらはRemixの<Form>と組み合わせるのが難しいため、 署名付きURLと組み合わせて使う方がメリットを享受しやすい
まとめ - ファイルサイズが小さい場合は、multipart/form-dataを活用したい - なによりシンプルに書けるのがメリット - ファイルサイズが大きい場合は、署名付きURLを活用したい - ユーザー体験を追求したい場合は、署名付きURLを活用したい