0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Cloudflare を使い倒す R2 編

Posted at

この記事は ひとりCloudflareを使い倒す Advent Calendar 2025 の6日目です

※まだまだチュートリアル的な備忘録が続きます

世の中にはアルファベット1文字と数字1文字で構成されるサービスがいろいろあります。

S3, R2, D1, ...(あんまりなかった)

とりあえず、R2 を使ってみます。

R2 って何さ

R2 はオブジェクトストレージです。

画像ファイルとか音楽ファイルとかをオブジェクトを言います。
それを保存できるストレージなので、オブジェクトストレージです。

普通のデータベースは構造化されていますよね。
この記事で言ったら、以下の JSON オブジェクトのように構造化されているといえます。

{
    "title": "Cloudflare を使い倒す R2 編",
    "author": "toreis-up"
}

どの記事でもこんな感じで扱えますよね。
これが構造化されている、ということです。
(※ラフに「構造化されている」を説明しているので、詳しい定義は調べてください。)

データは 99.999999999% (eleven 9) と、S3 と同じレベルのデータ耐久性を誇り、可用性も SLA で 99.9% と、高い水準です。

例えば、10,000,000 オブジェクトを 1 年で書き込んだとして、1つのオブジェクトがバグってロスするのに 10,000 年かかる計算です。とんでもねえ。

また、S3 互換なので、S3 を使っている製品は R2 に代替できるのではないでしょうか。

ん?R と S 、2 と 3…減って増えてる… (理由は知らない)

R2 を Hono で使ってみる

例によって、Hono で R2 を使ってみます。
今回は、ファイルを投稿するエンドポイントと、ファイルの一覧を出すエンドポイント、そしてファイルをダウンロードするエンドポイントを作ってみます。

セットアップ

pnpm create cloudflare@latest <dir> でプロジェクトを作って、Hono のプロジェクトテンプレートを立ち上げます。

pnpm install でプロジェクトの設定が終わったら、wrangler.jsonc を書き換えます。

wrangler.jsonc
{
-  "name": "<TBD>",
+  "name": "todo",
  "main": "src/index.ts",
-  "compatibility_date": "<TBD>",
+  "compatibility_date": "2025-12-06", // 今日の日付
-  "assets": {
-    "binding": "ASSETS",
-    "directory": "./public"
-  }
}

pnpm run dev で動くか確認します。

R2 のセットアップ

R2 は、まずバケットを設定する必要があります。

バケットとは:
簡単に言うと、ファイル置き場です。バケットにファイル (オブジェクト) を入れることができます。

さて、そしたら実際にバケットを立てましょう。

pnpm wrangler r2 bucket create hono-bucket
 ⛅️ wrangler 4.53.0
───────────────────
Creating bucket 'hono-bucket'...
✅ Created bucket 'hono-bucket' with default storage class of Standard.
To access your new R2 Bucket in your Worker, add the following snippet to your configuration file:
{
  "r2_buckets": [
    {
      "bucket_name": "hono-bucket",
      "binding": "hono_bucket"
    }
  ]
}
√ Would you like Wrangler to add it on your behalf? ... yes
√ What binding name would you like to use? ... hono_bucket
√ For local dev, do you want to connect to the remote resource instead of a local resource? ... no

そしたら、pnpm run cf-typegen で型定義を自動生成します。

おわり!これでバケットが立ちました。

R2 を Hono から呼ぶ

ファイルをアップロードする

Hono はファイルアップロードに対応しています。

この機能を使って、ファイルが受け取れるように変更します。

src/index.ts
import { Hono } from "hono";

const app = new Hono<{ Bindings: CloudflareBindings }>();

app.post("/file", async (c) => {
  const body = await c.req.parseBody()
  const file = body['file']  // Access the uploaded file here

  if (!file || typeof file === 'string') {
    return c.text("No file uploaded", 400);
  }

  const r2 = c.env.hono_bucket;

  await r2.put(file.name, file.stream(), {
    httpMetadata: {
      contentType: file.type,
    },
  });

  return c.text("File uploaded successfully!");
});

export default app;

そしたらサーバーと Postman を起動します。

Postman の Body を form-data に、Key を file にして、Key の右側にある Text となっているプルダウンから File を選択します。
そして Value に好きなファイルを指定して localhost:8787/file に POST してみると…

image.png

File uploaded successfully! ということで、ファイルがバケットに打ち上げられました。

ファイル一覧を取得する

バケットのファイル一覧は簡単に取得できます。

await r2.list() で呼んであげるだけです。

src/index.ts
// app.post...

+ app.get("/file", async (c) => {
+   const r2 = c.env.hono_bucket;
+   const files = await r2.list();
+ 
+   const fileNames = files.objects.map((obj) => obj.key);
+ 
+   const response = `Files in R2 Bucket:\n` + fileNames.join('\n');
+   return c.text(response);
+ })

// export ...

これだけです。

localhost:8787/file を叩いてみますと…

image.png

取れました。

ファイルをダウンロードする

ファイルをアップロードできるなら、ダウンロードもできるべきです。

ということで以下のコードを実装します。

src/index.ts
// app.get("file", ...

+ app.get("/file/:filename", async (c) => {
+   const filename = c.req.param("filename");
+   const r2 = c.env.hono_bucket;
+ 
+   const object = await r2.get(filename);
+ 
+   if (!object) {
+     return c.text("File not found", 404);
+   }
+ 
+   return c.body(object.body, {
+     headers: {
+       "Content-Type": object.httpMetadata?.contentType || "application/octet-stream",
+     },
+   });
+ });

// export ...

そして、さっきアップロードしたファイル名を file.ext とすると、localhost:8787/file/file.ext にアクセスすると…

image.png

返ってきました!:D

Postman ではわかりませんが、音声ファイルなども返ってきます。ブラウザで確認してみるとよいでしょう。

おわりに

またしてもローカロリーになってしまいました…

S3 の簡単な使いかたを自分が理解するだけの記事ですが、ちょっとだけ入門してみたい誰かのためになれば幸いです。

R2 と Cloudflare Images を組み合わせるとなにかが出来上がる気もしますよね。(ネタバレ)
いつか挑戦してみたいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?