見出し画像

Cloudflare WorkersとD1を試した記録

概要

Cloudflare Workersを試したときの記録です。初心者です。
Cloudflare Workers · Cloudflare Workers docs

Cloudflare D1 · Cloudflare D1 docs
を参考にしています。

Get startedに従いWorkersプロジェクトを作る

Get started guide · Cloudflare Workers docs
に従いました。このnoteの内容はほぼ書かれている通りに実行しただけです。

$ npm create cloudflare@latest

でcreate-cloudflare@2.21.1がインストールされました。
そしてプロンプトに従い下記を選択しました。

  • Workerのプロジェクトディレクトリ: testworkerにしました

  • アプリケーションのタイプ: "Hello World" Worker

  • TypeScriptを使うか: No

  • Gitを使うか: No

  • アプリケーションをデプロイするか: No

出てきたメッセージのとおりプロジェクトディレクトリ(testworker)で

$ npm run start

で開発サーバが起動しました。

$ npm run deploy

でCloudflareにデプロイできました。
デプロイするとhttps://<YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.devでアクセスできるようになりました。
またWeb Consoleにも表示されました。

消すときはWeb Consoleから消しました。

WorkersとD1のプロジェクトを作る

Workersの作り方が分かったので次にWorkersとD1のプロジェクトを作りました。
はじめに ·Cloudflare D1ドキュメント
に従いました。このnoteの内容はほぼ書かれている通りに実行しただけです。

$ npm create cloudflare@latest d1-tutorial

でプロジェクトを作りました。

  • Workerのプロジェクトディレクトリ: 引数で付けたd1-tutorialになりました

  • アプリケーションのタイプ: "Hello World" Worker

  • TypeScriptを使うか: Yes

  • Gitを使うか: No

  • アプリケーションをデプロイするか: No

次にデータベースを作成しました。

$ npx wrangler d1 create prod-d1-tutorial

これでWeb Consoleにデータベースができていました。

またwrangler.tomlファイルにDBとの接続情報があるためデータベース作成時に出力されたメッセージの内容を記載しました。

[[d1_databases]]binding = "DB"
database_name = "prod-d1-tutorial"
database_id = "16進数と-のID"

schema.sqlファイルに下記を書きました。

CREATE TABLE IF NOT EXISTS Customers (CustomerId INTEGER PRIMARY KEY, CompanyName TEXT, ContactName TEXT);
INSERT INTO Customers (CustomerID, CompanyName, ContactName) VALUES (1, 'Alfreds Futterkiste', 'Maria Anders'), (4, 'Around the Horn', 'Thomas Hardy'), (11, 'Bs Beverages', 'Victoria Ashworth'), (13, 'Bs Beverages', 'Random Name');

$ npx wrangler d1 execute prod-d1-tutorial --remote --file=./schema.sql
と実行しWeb Consoleからはテーブルが見えました。
そしてGet startedに書いてある通りにsrc/index.tsにペーストして
npm run deployでCloudflareにworkerをデプロイしました。
https://d1-tutorial.<YOUR_SUBDOMAIN>.workers.dev/api/beverages
にアクセスして動作していることが確認できました。

WorkersでIPを取得する

CF-Connecting-IPヘッダーで取得できました。IPv6だったとしてもCF-Connecting-IPヘッダーに入っていました。
Workersから下記で取得できました。

request.headers.get('CF-Connecting-IP')

CORSのHeaderを付ける

CORS header proxy · Cloudflare Workers docs
を参考にしました。

export default {
	async fetch(request, env): Promise<Response> {
		// CORSのレスポンス定義
		const corsHeaders = {
			"Access-Control-Allow-Origin": "https://alloworigin.example.com",
			"Access-Control-Allow-Methods": "GET,HEAD,POST,OPTIONS",
			"Access-Control-Max-Age": "86400",
		};
		// OPTIONに対する定義
		async function handleOptions(request: any) {
			if (
				request.headers.get("Origin") !== null &&
				request.headers.get("Access-Control-Request-Method") !== null &&
				request.headers.get("Access-Control-Request-Headers") !== null
			) {
				// CORS preflightのOPTIONにレスポンスする
				return new Response(null, {
					headers: {
						...corsHeaders,
						"Access-Control-Allow-Headers": request.headers.get("Access-Control-Request-Headers"),
					},
				});
			} else {
				// 普通のOPTIONSにレスポンスする
				return new Response(null, {
					headers: {
						Allow: "GET, HEAD, POST, OPTIONS",
					},
				});
			}
		}
		if (request.method === "OPTIONS") {
			return handleOptions(request);
		}
		const { pathname } = new URL(request.url);
		if (pathname === "/api/list") {
			const { results } = await env.DB.prepare(
				"SELECT * FROM mytable"
			).all();
			let response = Response.json(results);
			response.headers.set("Access-Control-Allow-Origin", corsHeaders["Access-Control-Allow-Origin"]);
			return response;
		}
	},
} satisfies ExportedHandler<Env>;

GETのクエリーパラメータを取得する

export default {
    async fetch(request, env): Promise<Response> {
        // リクエストURLを取得
		const url = new URL(request.url);
		// queryパラメータを取得
		const queryParams = url.searchParams;
        // ↓で取得できました。
        queryParams.get('id');

ArrayBufferのバイナリデータをブラウザへレスポンスする

これでレスポンスできました。

// レスポンスの作成
let response = new Response(binaryData, {
	headers: {
		'Content-Type': 'binary/octet-stream',
		'Content-Length': arrayBuffer.byteLength
	}
});
return response;

最後にD1の制限

生のSQLiteより厳しい制限がありました。作りたいものが出来なかったのでここまで調べて諦めました。
Limits · Cloudflare D1 docs
Freeだとデータベースが500MBまで、1行もしくくはBLOBで1MBまででした。
Workersで見えるlogだとエラー時にExceptionメッセージが見えていました。

"stack": " at D1Database._sendOrThrow (cloudflare-internal:d1-api:66:19)\n at async D1PreparedStatement.all (cloudflare-internal:d1-api:181:46)\n at async Object.fetch (index.js:53:29)",
"name": "Error",
"message": "D1_ERROR: string or blob too big",

この記事が気に入ったらサポートをしてみませんか?