imgurのようなシステムを自前で構築できないかと思い、Cloudflare WorkersとR2を用いて画像投稿システムを構築したのでそれの紹介をします。
どのようなシステムか?
https://i.smdr.io にapplication/octet-streamでファイルを送信すると、画像URLが返却されるシステムです。
画像ファイルはCloudflare R2に保存され、https://i.smdr.io/slug にアクセスすると3600秒のCacheつきで画像ファイルが返却されます。
画像をアップロードする
やっていることは単純で、トークン認証しつつMath.random().toString(32).substring(6)
でslugを生成し、URLを返却しているだけです。
async function postImage(request: Request, env: Env): Promise<Response> {
if (request.headers.get("X-API-TOKEN") !== env.API_TOKEN) return new Response("Unauthorized", {status: 401})
const url = new URL(request.url);
const name = url.pathname === "/" ? Math.random().toString(32).substring(6) : url.pathname.replaceAll("/", "")
await env.IMAGES.put(name, request.body, {
httpMetadata: {
contentType: "image/png"
}
})
return new Response(`https://i.smdr.io/${name}`)
}
画像を取得する
こちらも単純に画像をR2から取得・Cacheしつつ返却しているだけです。
async function getImage(request: Request, env: Env, context: ExecutionContext) {
const url = new URL(request.url);
const cacheKey = new Request(url.toString(), request);
const cache = caches.default;
let response = await cache.match(cacheKey);
if (!response) {
response = await getImageFromBucket(url.pathname.replaceAll("/", ""), env)
response = new Response(response.body, response)
response.headers.append('Cache-Control', 's-maxage=120');
context.waitUntil(cache.put(cacheKey, response.clone()))
}
return response
}
async function getImageFromBucket(name: string, env: Env): Promise<Response> {
const object = await env.IMAGES.get(name);
if (!object || !object.body) {
return new Response(`Object Not Found: ${name}`, {status: 404})
}
const headers = new Headers();
object.writeHttpMetadata(headers);
headers.set('etag', object.httpEtag);
return new Response(object.body, {
headers,
});
}
etagについて知らないので、etag周りは公式サンプルコピペです(:3」∠)_
これでcurlなどからアップロードすることができるようになりました。
curl https://i.smdr.io/ -X POST -H "X-API-TOKEN:..." --data-binary @face.jpeg --header "Content-Type:application/octet-stream"
ただ、これだとアップロードがかなり面倒なので、Appleのショートカットを利用して「imgurにアップロード」と同じようにできるようにします。
ショートカットからアップロードする
(この画像もi.smdr.ioを利用しています)
共有シートなどから画像もしくはファイルを受け取り、i.smdr.ioにリクエストし、その内容をコピーしています。こうすることでiPhone・Mac両対応をしています。
作ってみて
Cloudflare R2は初めて触ったのですが、かなり使いやすい印象でした。get,putしか利用していませんがメタデータだけ取得するなどできさまざまな用途に使えるなと思いました。