Cloudflare R2を使ってファイル管理を行うための基礎
本文書はCloudflareのR2を利用してクラウド上にデータを保存したいと思っているが利用するためにはクレジッドカードの情報を入力する必要があるため戸惑っている人、R2へのファイルのアップロードなど基本的な利用方法を知りたいといった入門者向けの内容でR2に関するサービスの説明ではなく実際に手を動かして理解を深めたい人向けの内容になっています。
Cloudflare R2を利用するためにはクレジットカードの入力が必要だということを認識の上読み進めてください。クレジットカードの情報を入力したからといって即座に課金が発生するわけではありません。無料枠も準備されています。
R2を利用するためのアカウントの作成からWrangler CLI, Cloudflare Workers, AWS CLI, aws-sdk-js-v3ライブラリによる ファイルのアップロード、ファイル一覧の取得などR2の基本操作について説明を行っています。
動作確認は macOS を利用して行っています。
目次
Cloudflare R2とは
Cloudflare R2はAWS S3互換クラウドベースのオブジェクトストレージサービスです。写真や音声、動画などを保存することができます。1ヶ月10GBまでは無料ですることができ、読み込み書き込みの制限はありますがエグレス料金(ダウンロードする際の下りの通信量)が無料であるため非常に安価に利用することができます。
Cloudflare のアカウントの作成
R2 を利用するために Cloudflare のアカウントを作成する必要があります。アカウントを作成するために R2 の製品ページにブラウザからアクセスします。Cloudflare のページを日本語で表示させたい場合は右上にある地球儀のアイコンをクリックして言語を変更してください。
画面の中央にある”Sign up”ボタンをクリックします。アカウントを作成するためにメールアドレスとパスワードを入力する必要があります。
メールアドレスとパスワードを入力すると入力したメールアドレス宛てにアカウントを認証するためのメールが送信されます。
受信したメールにはリンクが含まれているのでリンクをクリックします。
クリックを行いサインアップが完了するとCloudflareのダッシュボードの Home ページが表示されます。アカウントの作成はこれで完了です。Cloudflare WorkersやCloudflare Pagesであればこの状態で利用することができます。
R2 の Activate(支払い情報入力)
R2 を利用するために左側のサイドメニューからR2を選択します。R2はサインアップするだけで利用できるわけではなく利用するためには支払い情報の登録を行う必要があります。
支払い情報を入力してもいいという人は”Activate R2”ボタンをクリックしてください。
料金の画面が表示されます。
無料枠は以下の通りです。無料枠を超えて利用すると支払いが発生します。
- 1,000,000 Class A operatios
- 10,000,000 Class B operations
- 10GB Storage
Class A operatoins に主に書き込みなどの処理でListBuckets, PutBucket, ListObjects, PutObject, CopyObject, CompleteMultipartUpload, CreateMultipartUpload, ListMultipartUploads, UploadPart, UploadPartCopy and PutBucketEncryptionの処理が含まれます。
Class B operations は主に読み込みなどの処理でHeadBucket, HeadObject, GetObject, UsageSummary, GetBucketEncryption and GetBucketLocationの処理が含まれます。
問題がない場合は”Proceed to Payment Details”ボタンをクリックします。クレジッドカード情報を入力する画面が表示されるので情報を入力して”Save Payment Information”ボタンをクリックしてください。
入力した支払い情報に問題がなければ購入完了画面が表示されます。
R2の設定
Bucket の作成
R2 が利用可能になると 概要画面が表示されます。R2 では Bucket を作成してファイルをオブジェクトとして Bucket の中に保存していきます。ダッシュボードから Bucket を作成することができるので”バケットを作成する”ボタンをクリックします。
動作確認のために利用する Bucket の名前にここでは”reffect”という名前をつけています。任意の名前をつけることができるので好きな名前をつけてください。自動を選択すると保存する場所が自動で決められます。近くの場所が選ばれるようになっています。管理を指定するを選択すると欧州EUを選択することができます。自動を選択して”バケットを作成する”ボタンをクリックします。
作成が完了すると以下の画面が表示されます。この画面からBucketに保存されているオブジェクトを確認することができます。作成したばかりなので画像は存在しないため Bucket の中身は空です。
ファイルのアップロード
ダッシュボードからファイルのアップロードを行うことができます。”バケットの準備ができています。ファイルを追加して開始します”をクリックすることで OS 上に保存されているファイルを選択することができます。Drag&Drop でもアップロードを行うことができます。
試しに Drag&Drop で”cloudflare-r2-1.png”ファイルをアップロードします。アップロードが完了するとオブジェクトストレージということでObjects列の下にアップロードしたファイル名が表示されます。
アップロードしたファイルは右側にある”…”ボタンをクリックすることでダウンロードすることもできます。必要であればアップロードした画像をダウンロードしてみてください。
ファイル名をクリックするとファイルの詳細情報が表示されます。
ファイルの公開
ファイルをインターネット上に公開するためには公開設定が必要となります。公開設定にはドメインを利用する方法とR2.devのサブドメインを利用する方法があります。ドメインの設定を行なっていない場合にはR2.dev subdomainを利用します。
Bucket 毎に設定を行うのでBucketの詳細画面で”Settings(設定)”タブをクリックします。下記の画面が表示されるので赤丸の”Allow Access”ボタンをクリックします。
Public アクセスを許可するかどうか確認の画面が表示されるので”allow”と入力して”Allow”ボタンをクリックします。
設定が完了すると Public R2.dev Bucket URL が表示されます。また公開を停止したい場合には”Disallow Access”ボタンから行うことができます。
設定後オブジェクトの詳細画面に行くと Public Bucket が表示され表示されている URL にアクセスするとアップロードした画像が表示されます。
ダッシュボードからのファイルのアップロードとインターネット上からのファイルのアクセス方法を確認することができました。
Wranglerコマンドによる操作
ダッシュボードからファイルのアップロードとアップロードしたファイルを確認しましたがR2に保存されているファイルを操作するためにはさまざまな方法があります。最初にWranglerコマンドを利用して操作を行います。
プロジェクトの作成
WranglerコマンドはR2に限定されたものではなくCloudflare上のサービスを操作する際に利用することができます。Wranglerコマンドを利用することでBucketの作成やファイルのアップロードを行うことができます。
Wranglerコマンドを利用するためにOS上で実行するパッケージをインストールする必要があります。wranglerは”npm install -g wrangler”でグローバルにインストールすることもできますが Cloudflare Workers のプロジェクトを”npm create cloudflare@latest”で作成するとwrangler パッケージ もインストールされるためこちらの方法を利用します。
“npm create cloudflare”コマンドを実行するとプロジェクト名、TypeScript の利用、テンプレートの選択、Deploy について質問されます。プロジェクト名はここでは cloudflare-r2-test としていますが任意の名前をつけてください。アプリケションのタイプは”Hello World” Worker, TypeScript は”Yes”, Deploy は”No”を選択しています。
% npm create cloudflare@latest
using create-cloudflare version 2.8.4
╭ Create an application with Cloudflare Step 1 of 3
│
╰ In which directory do you want to create your application? also used as applic├ In which directory do you want to create your application?
│ dir ./cloudflare-r2-test
│
├ What type of application do you want to create?
│ type "Hello World" Worker
│
├ Do you want to use TypeScript?
│ yes typescript
│
├ Copying files from "hello-world" template
│
├ Retrieving current workerd compatibility date
│ compatibility date 2023-12-18
│
├ Do you want to use git for version control?
│ yes git
│
╰ Application created
╭ Installing dependencies Step 2 of 3
│
├ Installing dependencies
│ installed via `npm install`
│
├ Installing @cloudflare/workers-types
│ installed via npm
│
├ Adding latest types to `tsconfig.json`
│ added @cloudflare/workers-types/2023-07-01
│
├ Committing new files
│ git commit
│
╰ Dependencies Installed
╭ Deploy with Cloudflare Step 3 of 3
│
├ Do you want to deploy your application?
│ no deploy via `npm run deploy`
│
├ APPLICATION CREATED Deploy your application with npm run deploy
│
│ Navigate to the new directory cd cloudflare-r2-test
│ Run the development server npm run start
│ Deploy your application npm run deploy
│ Read the documentation https://developers.cloudflare.com/workers
│ Stuck? Join us at https://discord.gg/cloudflaredev
│
╰ See you again soon!
プロジェクトの作成が完了するとプロジェクト名のフォルダが作成されるので移動してインストールした wrangler のバージョンを確認しておきます。
% cd cloudflare-r2-test
% npx wrangler --version
⛅️ wrangler 3.22.1
-------------------
package.json の中身も確認しておきます。
{
"name": "cloudflare-r2-test",
"version": "0.0.0",
"private": true,
"scripts": {
"deploy": "wrangler deploy",
"dev": "wrangler dev",
"start": "wrangler dev"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20231218.0",
"typescript": "^5.0.4",
"wrangler": "^3.0.0"
}
}
ログイン
wrangler コマンドを利用してR2を操作するためにCloudflareへのログインが必要になります。ログインは”npx wrangler login”コマンドで行います。
% npx wrangler login
⛅️ wrangler 3.22.1
------------------
Attempting to login via OAuth...
Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20d1%3Awrite%20pages%3Awrite%20zone%3Aread%20ssl_certs%3Awrite%20constellation%3Awrite%20offline_access&state=girJ-rC~Yvm8~pEmzB0xDrpj~RMiHu-F&code_challenge=a3vUQIutP83UMUvbezxPabf2mjIG3ClSzvZ_OP_CpgI&code_challenge_method=S256
Successfully logged in.
自動でブラウザが起動してダッシュボードにログインしている場合には”Allow Wrangler to make changes to your Cloudflare account?”の画面が表示されるので”Allow”を選択します。ダッシュボードにログインしていない場合には ID とパスワードを聞かれるので入力してください。ログインが完了すると画面には”You have granted authorization to Wrangler!”が表示されます。これで wrangler コマンドを利用してクラウド上のサービスを操作できるようになります。
ログインに成功するとwranglerコマンドでR2を操作することができます。
ファイルのアップロード
プロジェクトフォルダ直下にcloudflare-r2-2.pngファイルを保存してwranglerコマンドを利用してファイルのアップロードを行います。
% npx wrangler r2 object put reffect/cloudflare-r2-2.png --file=cloudflare-r2-2.png
⛅️ wrangler 3.22.1
------------------
Creating object "cloudflare-r2-2.png" in bucket "reffect".
Upload complete.
ダッシュボードで確認するとファイルのアップロードが正常に行われていることが確認できます。
ファイルのダウンロード
wrangler コマンドを利用して bucket に保存されているファイルをローカルにダウンロードすることもできます。reffect Bucketに保存済みのcloudflare-r2-1.pngファイルをダウンロードしています。
% npx wrangler r2 object get reffect/cloudflare-r2-1.png
⛅️ wrangler 3.22.1
------------------
Downloading "cloudflare-r2-1.png" from "reffect".
Download complete.
ファイルの削除
ファイルの削除も wrangler コマンドを利用して行うことができます。
% npx wrangler r2 object delete reffect/cloudflare-r2-2.png
⛅️ wrangler 3.22.1
------------------
Deleting object "cloudflare-r2-2.png" from bucket "reffect".
Delete complete.
wrangler コマンドを利用したR2の操作方法を理解することができました。
AWS CLI による操作
AWS CLIはAWSをコマンドラインで操作するためのAWS 用のツールですがR2でも利用することができます。AWS CLIは、Windows, macOS, LinuxのOS向けに提供されており利用するためには OS にインストールを行う必要があります。
AWS CLI のインストール
本文書では macOS を利用しているので HomeBrew を利用して AWS CLI のインストールを行います。
インストールする awscli の情報を brew info コマンドを利用して確認します。バージョンは 2.11.27 で Not installed と表示されているのでインストールが行われていないことが確認できます。
% brew info awscli
==> awscli: stable 2.15.0 (bottled), HEAD
Official Amazon AWS command-line interface
https://aws.amazon.com/cli/
Not installed
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/awscli.rb
License: Apache-2.0
==> Dependencies
Build: cmake ✘, pkg-config ✘, rust ✘
Required: cffi ✘, docutils ✘, openssl@1.1 ✔, pycparser ✘, python@3.11 ✘, six ✘
==> Options
--HEAD
Install HEAD version
==> Caveats
The "examples" directory has been installed to:
/usr/local/share/awscli/examples
==> Analytics
install: 173,438 (30 days), 302,393 (90 days), 337,869 (365 days)
install-on-request: 169,819 (30 days), 298,774 (90 days), 334,250 (365 days)
build-error: 0 (30 days)
インストールはbrew installコマンドで行います。
% brew install awscli
インストールが完了後—versionオプションでバージョンを確認することができます。
% aws --version
aws-cli/2.15.6 Python/3.11.6 Darwin/22.6.0 source/x86_64 prompt/off
API Token の作成
AWS CLI を利用してR2を操作するためにAPI Tokenが必要となります。API TokenはCloudflareのダッシュボードから作成することができます。
ダッシュボードのR2のOverview画面の右上にある”Manage R2 API Tokens”をクリックします。
API Tokensの画面が表示されるので”Create API token”ボタンをクリックします。
Bucketのオブジェクトの作成などが行えるように”Admin Read & Write”か”Object Read & Write”を選択して”Create API Token”ボタンをクリックします。
作成が完了すると表示される”Access Key ID”と”Secret Access Key”が必要となります。この情報は他の人に見せないように大切に保管してください。また後でキーを確認することができないのでKeyの情報は確実に控えておいてくだい。
API Token の設定
API Token の作成が完了したら”aws configure”コマンドを実行して設定を行います。コマンドを実行すると下記のように”Access Key ID”などを聞かれるので各自が作成したAPI Tokenの値を設定してください。region name は”auto”, output format は”json”を設定します。
% aws configure
AWS Access Key ID [None]: 2627242a9c1bf30695b2c1241cab8ac9
AWS Secret Access Key [None]: 8d893715f1410b681ce31e5fe0eab2159c018d45f355924ca932a73c861c5796
Default region name [None]: auto
Default output format [None]: json
設定した内容はユーザのホームディレクトリ直下の.aws フォルダの中に config, credentials ファイルとして保存されます。
AWS のツールを利用してR2を操作する場合は”https://<ACCOUNT_ID>.r2.cloudflarestorage.com”のエンドポイントに対して実行します。ACCOUNT_ID は各自によって異なる値になり, R2のOverview画面の右側に表示されています。
Bucket の確認
aws コマンドを利用してBucketの一覧を表示させます。コマンドを実行すると Bucket の reffect を確認することができます。もしToken作成時に”Admin Read & Write”を選択していない場合には”An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied”のメッセージが表示されます。
% aws s3api list-buckets --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com
{
"Buckets": [
{
"Name": "reffect",
"CreationDate": "2023-07-03T01:30:16.236000+00:00"
}
],
"Owner": {
"DisplayName": "a51248e16eb1cfe6a9a262e7XXXXX",
"ID": "a51248e16eb1cfe6a9a262e7XXXXX"
}
}
“aws s3″コマンドでも可能です。
% aws s3 --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com ls
2023-07-03 10:30:16 reffect
Bucket内のオブジェクトを確認する場合は”aws s3api list-objects”コマンドを利用します。ダッシュボードでアップロードした cloudflare-r2-1.png の情報が表示されます。
% aws s3api list-objects --bucket reffect --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com
{
"Contents": [
{
"Key": "cloudflare-r2-1.png",
"LastModified": "2023-07-05T05:14:19.516000+00:00",
"ETag": "\"71c67fbd5fa5510ef2e5a576d22236e8\"",
"Size": 856183,
"StorageClass": "STANDARD",
"Owner": {
"DisplayName": "a51248e16eb1cfe6a9a262e7XXXXX",
"ID": "a51248e16eb1cfe6a9a262e7XXXXX"
}
}
],
"RequestCharged": null
}
ファイルのアップロード
AWS CLI コマンドを利用してローカルに保存している cloudflare-r2-2.png ファイルをアップロードします。
% aws s3api put-object --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com --bucket reffect --key cloudflare-r2-2.png --body cloudflare-r2-2.png
{
"ETag": "\"3c76af5c7b73361aaa4b0e90b4e5f170\"",
"VersionId": "7e76db1ca2a73bc83af43377c7052259"
}
“AWS CLI”を利用することで”R2″の操作が行えることが確認できました。
@aws-sdk/client-s3を利用した場合
ここまでは主にコマンドを利用してR2の操作を行ってきましたがここでは@aws-sdk/client-s3ライブラリを利用してR2の操作を行います。
プロジェクトの作成
プロジェクトフォルダ”aws-sdk-r2”を作成します。作成したプロジェクトフォルダで@aws-sdk/client-s3 をインストールして利用します。
% mkdir aws-sdk-r2
% cd aws-sdk-r2
“npm init -y”コマンドを実行してpackage.jsonファイルを作成します。
% npm init -y
Wrote to /Users/mac/Desktop/aws-sdk-r2/package.json:
{
"name": "aws-sdk-r2",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
@aws-sdk/client-s3 のインストール
@aws-sdk/client-s3 のインストールを行います。
% npm install @aws-sdk/client-s3
@aws-sdk/client-s3 を利用する際も API Token を利用するため dotenv ライブラリのインストールを行い環境変数を利用して設定します。
% npm install dotenv
import 文が利用できるように package.json ファイルに”type”:“module”を追加します。
{
"name": "aws-sdk-r2",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@aws-sdk/client-s3": "^3.484.0",
"dotenv": "^16.3.1"
},
"type": "module"
}
.env ファイルを作成して “ACCESS KEY ID” と “SECRET ACCESS KEY” の設定を行います。ENDPOINT の設定も.env ファイルに設定しておきます。
R2_ACCESS_KEY_ID=2627242a9c1bf30695b2c1241cab8ac9
R2_SECRET_ACCESS_KEY=8d893715f1410b681ce31e5fe0eab2159c018d45f355924ca932a73c861c5796
ENDPOINT=https://a51248e16eb1cfe6a9a262e7XXXXX.r2.cloudflarestorage.com
Bucket の情報取得
index.js ファイルを作成しコードを記述します。@aws-sdk/client-s3 から import した S3Client を利用して S3 インスタンスを作成します。インスタンスを作成する際に”ACCESS KEY ID” と “SECRET ACCESS KEY”を指定します。ListBucketsCommand で R2 に作成されいてる Buskets の情報を取得し、ListObjectsV2Command で Bucket の reffect に保存されているオブジェクトの一覧を取得しています。Token作成時に”Admin Read & Write”を選択していない場合はListBucketsCommandの行は削除してください。
import {
S3Client,
ListBucketsCommand,
ListObjectsV2Command,
} from '@aws-sdk/client-s3';
import dotenv from 'dotenv';
dotenv.config();
const S3 = new S3Client({
region: 'auto',
endpoint: process.env.ENDPOINT,
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY_ID,
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
},
});
console.log(await S3.send(new ListBucketsCommand('')));
console.log(await S3.send(new ListObjectsV2Command({ Bucket: 'reffect' })));
index.js ファイルの作成ができたら、node コマンドを利用して index.js ファイルを実行します。Bucket の情報と Bucket 内のオブジェクトの情報が表示されていることが確認できます。
% node index.js
{
'$metadata': {
httpStatusCode: 200,
requestId: undefined,
extendedRequestId: undefined,
cfId: undefined,
attempts: 1,
totalRetryDelay: 0
},
Buckets: [ { Name: 'reffect', CreationDate: 2023-07-03T01:30:16.236Z } ],
Owner: {
DisplayName: 'a51248e16eb1cfe6a9a262e7XXXXX',
ID: 'a51248e16eb1cfe6a9a262e7XXXXX'
}
}
{
'$metadata': {
httpStatusCode: 200,
requestId: undefined,
extendedRequestId: undefined,
cfId: undefined,
attempts: 1,
totalRetryDelay: 0
},
Contents: [
{
Key: 'cloudflare-r2-1.png',
LastModified: 2023-07-05T05:14:19.516Z,
ETag: '"71c67fbd5fa5510ef2e5a576d22236e8"',
Size: 856183,
StorageClass: 'STANDARD'
},
{
Key: 'cloudflare-r2-2.png',
LastModified: 2023-07-05T07:10:28.139Z,
ETag: '"3c76af5c7b73361aaa4b0e90b4e5f170"',
Size: 339875,
StorageClass: 'STANDARD'
}
],
IsTruncated: false,
KeyCount: 2,
MaxKeys: 1000,
Name: 'reffect'
}
ファイルのアップロード
ローカルに保存した cloudflare-r2-3.png ファイルを@aws-sdk/client-s3 を利用してアップロードする方法を確認します。アップロードにはPubObjectCommandを利用します。ファイルアップロード後に Bucket に保存されているオブジェクトをListObjectV2Commandを利用して取得しています。fs.createReadStreamメソッドを利用して保存したファイルを指定しています。
import fs from 'fs';
import {
S3Client,
PutObjectCommand,
ListObjectsV2Command,
} from '@aws-sdk/client-s3';
import dotenv from 'dotenv';
dotenv.config();
const S3 = new S3Client({
region: 'auto',
endpoint: process.env.ENDPOINT,
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY_ID,
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
},
});
await S3.send(
new PutObjectCommand({
Body: fs.createReadStream('cloudflare-r2-3.png'),
Bucket: 'reffect',
Key: 'cloudflare-r2-3.png',
})
);
console.log(await S3.send(new ListObjectsV2Command({ Bucket: 'reffect' })));
node index.js コマンドを実行します。ListObjectsV2Command の結果によりアップロードしたファイルが追加されていることが確認できます。
% node index.js
{
'$metadata': {
httpStatusCode: 200,
requestId: undefined,
extendedRequestId: undefined,
cfId: undefined,
attempts: 1,
totalRetryDelay: 0
},
Contents: [
{
Key: 'cloudflare-r2-1.png',
LastModified: 2023-07-05T05:14:19.516Z,
ETag: '"71c67fbd5fa5510ef2e5a576d22236e8"',
Size: 856183,
StorageClass: 'STANDARD'
},
{
Key: 'cloudflare-r2-2.png',
LastModified: 2023-07-05T07:10:28.139Z,
ETag: '"3c76af5c7b73361aaa4b0e90b4e5f170"',
Size: 339875,
StorageClass: 'STANDARD'
},
{
Key: 'cloudflare-r2-3.png',
LastModified: 2023-07-05T09:55:09.850Z,
ETag: '"0e72511b51cd30247221fdf3d31d6245"',
Size: 324244,
StorageClass: 'STANDARD'
}
],
IsTruncated: false,
KeyCount: 3,
MaxKeys: 1000,
Name: 'reffect'
}
@aws-sdk/client-s3 を利用したファイルのアップロードと Bucket に保存されているファイル一覧を確認することができました。
Cloudflare Workersによる設定
プロジェクトはwranglerコマンドを利用する際に作成した”cloudflare-r2-test”プロジェクトを使います。これまでの動作確認とは異なり入力フォームを利用してPOSTリクエストを利用します。POSTリクエストで送信したデータをWorkersが受け取り、WorkersからR2にファイルのアップロードを行います。
index.html ファイルの作成
プロジェクトフォルダの直下に index.html ファイルを作成して入力フォームを追加します。fetch 関数の URL に設定している”http://127.0.0.1:8787/“はWorkersが開発時に利用する開発サーバのURLです。後ほど実行すると”npx wrangler dev”のコマンド後に表示されるURLを記述してください。EventListenerでchangeイベントを設定しているのでinput要素でファイルを選択したらuploadImage関数が実行されます。
<!DOCTYPE html>
<html>
<head>
<title>Upload Images</title>
</head>
<body>
<h1>File Upload</h1>
<form>
<label for="" image>File Select:</label>
<input type="file" name="image" id="image" />
</form>
<script>
async function uploadImage(file) {
fetch('http://127.0.0.1:8787/', {
method: 'POST',
body: file,
})
.then((response) => response.text())
.then((data) => console.log(data))
.catch((error) => console.error(error));
}
const image = document.getElementById('image');
image.addEventListener('change', (e) => {
const formData = new FormData();
console.log(e.target.files[0]);
formData.append('file', e.target.files[0]);
uploadImage(formData);
});
</script>
</body>
</html>
Workers 側の設定
Workers の設定はsrcフォルダのindex.tsファイルで行います。WorkersからR2へのファイルのアップロードにはputメソッドを利用します。putメソッドの第一引数にはkeyを設定します。ここではkeyをファイル名としています。第二引数には value を設定しますが value は ReadableStream, ArrayBuffer, ArraryBufferView, string, null, Blog を指定することができます。ここでは受け取ったファイルを指定しています。第三引数にはオプションでファイルの Content-Type を指定しています。
export default {
export interface Env {
MY_BUCKET: R2Bucket;
}
export default {
async fetch(request: Request, env: Env) {
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
};
const formData = await request.formData();
const file = formData.get('file') as File;
const fileName = file.name;
const contentType = file.type;
const fileBuffer = await file.arrayBuffer();
try {
await env.MY_BUCKET.put(fileName, fileBuffer, {
httpMetadata: {
contentType,
},
});
} catch (err) {
console.log(err);
}
return new Response('image uploaded successfully ', {
headers: {
...corsHeaders,
},
});
},
};
env.MY_BUCKET で設定している環境変数は wrangler.toml ファイルで行います。wrangler.toml ファイルは Worker プロジェクトを作成時に自動で作成されており R2 Bucket についての情報も登録されていますがコメントされています。コメントを外し各環境にあった値に変更します。bucket_name はここでは reffect になります。
name = "cloudflare-r2-test"
main = "src/index.ts"
compatibility_date = "2023-12-18"
//略
# Bind an R2 Bucket. Use R2 to store arbitrarily large blobs of data, such as files.
# Docs: https://developers.cloudflare.com/r2/api/workers/workers-api-usage/
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "reffect"
preview_bucket_name = "reffect"
開発環境で Workersの動作確認を行う場合はpackage.jsonに登録されているscriptの”npm run start”コマンドを利用しますが開発環境でクラウド上のR2を利用する場合は”npx wrangler dev —remote”とオプションの”—remote”をつけて起動させます。
”npx wrangler dev —remote”を実行した際に wrangler.toml ファイルの中で preview_bucket_name を設定していない場合にはエラーが発生します。エラーでは本番用ではなく開発用の Bucket を用意して wrangler.toml ファイルの preview_bucket_name に設定するように言っています。ここでは動作確認で本番用ではないので同じ Bucket を利用しています。
% npx wrangler dev --remote
⛅️ wrangler 3.22.1
------------------
✘ [ERROR] In development, you should use a separate r2 bucket than the one you'd use in production. Please create a new r2 bucket with "wrangler r2 bucket create <name>" and add its name as preview_bucket_name to the r2_buckets "MY_BUCKET" in your wrangler.toml
ファイルのアップロードの動作確認
作成した index.html ファイルを開くと下記の画面が表示されます。
“npx wrangler dev —remote”コマンドで Workers の開発サーバを起動します。
% npx wrangler dev --remote
⛅️ wrangler 3.22.1
------------------
Your worker has access to the following bindings:
- R2 Buckets:
- MY_BUCKET: reffect
[wrangler:inf] Ready on http://localhost:63877
Total Upload: 1.77 KiB / gzip: 0.86 KiB
Total Upload: 5.21 KiB / gzip: 1.58 KiB
index.html画面からファイルを選択するとindex.htmlファイルで指定したfetch関数のurlに対してPOSTリクエストが送信されます。そのUrlに設定したPORTでWorkersがPOSTリクエストを受け取ります。
アップロードに成功した場合はブラウザのデベロッパーツールのコンソールに”image uploaded successfully”が表示され Cloudflare のダッシュボードを見るとアップロードしたファイルが Bucket の中に保存されているはずです。この後に Workers からアップロードしたファイルの確認も行います。
index.html ファイルから送信されてくる POST リクエストの Headers の情報を確認したい場合は以下のように行うことで確認ができます。
const { headers } = request;
let headersObject = Object.fromEntries(headers);
let requestHeaders = JSON.stringify(headersObject, null, 2);
console.log(`Request headers: ${requestHeaders}`);
今回のコードであれば”npx wrangler dev —remote”を実行したターミナルに headers 情報が表示されます。
Request headers: {
"accept": "*/*",
"accept-encoding": "gzip",
"accept-language": "ja,en-US;q=0.9,en;q=0.8",
"cf-connecting-ip": "123.223.41.4",
"cf-ew-preview-server": "https://22m228.cfops.net",
"cf-ipcountry": "JP",
"cf-ray": "4e23b4c6afa1f8d7",
"cf-visitor": "{\"scheme\":\"https\"}",
"connection": "Keep-Alive",
"content-length": "278582",
"content-type": "multipart/form-data; boundary=----WebKitFormBoundarynmBfH7Q2Y72Di6MJ",
"host": "cloudflare-r2-test.johndoe.workers.dev",
"origin": "http://127.0.0.1:5500",
"referer": "http://127.0.0.1:5500/",
"sec-ch-ua": "\"Not.A/Brand\";v=\"8\", \"Chromium\";v=\"114\", \"Google Chrome\";v=\"114\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"macOS\"",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-site",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
"x-forwarded-proto": "https",
"x-real-ip": "123.223.41.4"
}
アップロードしたファイルの確認
ファイルを Bucket に保存したい場合には put メソッドを利用しましたが Bucket のオブジェクトの一覧を取得したい場合には list メソッドを利用することができます。ファイルアップロードに利用した worker.js ファイルを利用していますが処理は request.method の値を確認して分岐させています。POST リクエストの場合はアップロード処理、それ以外のリクエストはオブジェクトの一覧を json データで戻すようにしています。
export default {
async fetch(request, env) {
if (request.method === 'POST') {
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
};
const formData = await request.formData();
const fileName = formData.get('file').name;
const contentType = formData.get('file').type;
const fileBuffer = await formData.get('file').arrayBuffer();
try {
await env.MY_BUCKET.put(fileName, fileBuffer, {
httpMetadata: {
contentType,
},
});
} catch (err) {
console.log(err);
}
return new Response('image uploaded successfully ', {
headers: {
...corsHeaders,
},
});
} else {
const objectLists = await env.MY_BUCKET.list();
const json = JSON.stringify(objectLists, null, 2);
return new Response(json, {
headers: {
'content-type': 'application/json;charset=UTF-8',
},
});
}
},
};
GETリクエストはブラウザから行うことができるのでURLにWorkers の開発サーバの URL(http://127.0.0.1:63877)を設定すると Bucket に保存されているオブジェクトの一覧が表示されます。
{
"objects": [
{
"uploaded": "2023-07-05T05:14:19.516Z",
"checksums": {
"md5": "71c67fbd5fa5510ef2e5a576d22236e8"
},
"httpEtag": "\"71c67fbd5fa5510ef2e5a576d22236e8\"",
"etag": "71c67fbd5fa5510ef2e5a576d22236e8",
"size": 856183,
"version": "7e76db86f8148115dde4b12ffae682e2",
"key": "cloudflare-r2-1.png"
},
//略
{
"uploaded": "2023-07-05T10:05:09.850Z",
"checksums": {
"md5": "f4eb01a95e3e071361e3772e1fa895f1"
},
"httpEtag": "\"f4eb01a95e3e071361e3772e1fa895f1\"",
"etag": "f4eb01a95e3e071361e3772e1fa895f1",
"size": 219896,
"version": "7e76d77dee49a653b2b6553ff4ab3679",
"key": "cloudflare-r2-4.png"
}
],
"truncated": false,
"delimitedPrefixes": []
}
Workersを利用してもR2の操作が行えることが確認できました。
WorkdersのDeploy
作成したWokersは”npx wrangler deploy”コマンドで実行することができます。
% npx wrangler deploy
⛅️ wrangler 3.22.1
-------------------
Your worker has access to the following bindings:
- R2 Buckets:
- MY_BUCKET: reffect
Total Upload: 1.03 KiB / gzip: 0.49 KiB
Uploaded cloudflare-r2-test (1.37 sec)
Published cloudflare-r2-test (3.82 sec)
https://cloudflare-r2-test.reffect_dev.workers.dev
Current Deployment ID: 4a507d4d-9081-497d-b96e-e4b9d7fb9750
Deployが完了したらindex.htmlのfetch関数のURLを表示されているURLに変更してください。今後はネット上に公開されたWorkersを利用してR2へのファイルの保存を行うことができます。
ここまでの動作確認でR2にファイルをアップロードするための方法をいくつも学ぶことができたのでCloudFlareのR2について基本的な知識もかなり身についたのではないでしょうか。