Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
RemixとCloudflare Stack におけるFile Upload
Search
Ossamoon
September 25, 2024
Programming
460
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
180
SSRアプリケーションにおけるPKCE付き認可コードフロー
ossamoon
0
78
Other Decks in Programming
See All in Programming
Crash Auto Pipelines
veronikapj
1
410
Spec-Driven Development - Why Vaadin Is the Perfect Fit
simas
PRO
0
240
AI-Powered Domain-Driven Design
ziobrando
0
430
小さなアプリを作って公開するまで
onozaty
0
160
AI駆動開発4年目の現在地(『あなたはFDEになるべきか?』イベント資料)
kumaiu
0
580
Kawaiicon: Kubernetes, it's no longer cool, but let's secure it anyway!
barnbarn
0
130
조합이폭발하는디자인시스템이걸눈으로도테스트하라고요
giljongyu
0
740
地方こそサーバーレス — 10年続けた、顔が見えるチームで確かな基盤を / Serverless Matters Most in Regional Areas — 10 Years of Building Reliable Foundations with Close-Knit Teams
seike460
PRO
1
340
自作Discord音声botをLambda MicroVMsに移行した話 / Migrating My Discord Voice Bot to Lambda MicroVMs
akihisaikeda
1
300
PumaからFalconに移行したRailsアプリケーションでの実践
falcon8823
0
370
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
230
作れるエンジニアから、価値を届けるエンジニアへ
ryunakayama
1
250
Featured
See All Featured
The World Runs on Bad Software
bkeepers
PRO
72
12k
How GitHub (no longer) Works
holman
316
150k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
980
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
750
Making the Leap to Tech Lead
cromwellryan
135
10k
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.5k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.6k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.4k
Writing Fast Ruby
sferik
630
63k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
3
3.9k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.9k
Producing Creativity
orderedlist
PRO
348
41k
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を活用したい