Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

大きな JSON をストリーミングする

ストリーミングを使って、大きな JSON のリクエスト / レスポンス本文を解析・変換します。

最終更新 Markdown で表示Agent セットアップ

Streams API を使うと、すべてをバッファすると Worker の 128 MB メモリ制限を超える JSON ペイロードを処理できます。ストリーミングでは、データが到着するにつれて JSON を段階的に解析・変換できます。ペイロード全体をメモリに載せるより速く、Worker はデータを段階的に処理し始められます。メモリ制限の範囲で、数 GB 規模のペイロードやファイルも扱えます。

@streamparser/json-whatwg ライブラリは、Web Streams API 互換のストリーミング JSON パーサーを提供します。

依存関係をインストールします。

npm install @streamparser/json-whatwg

JSON リクエスト本文をストリーミングする

この例では、大きな JSON リクエスト本文を解析し、ペイロード全体をメモリに載せずに特定のフィールドを抽出します。

import { JSONParser } from "@streamparser/json-whatwg";

export default {
	async fetch(request): Promise<Response> {
		const parser = new JSONParser({ paths: ["$.users.*"] });

		const users: string[] = [];

		// Pipe the request body through the JSON parser
		const reader = request.body
			.pipeThrough(parser)
			.getReader();

		// Process matching JSON values as they stream in
		while (true) {
			const { done, value } = await reader.read();
			if (done) break;
			// Extract only the name field from each user object
			if (value.value?.name) {
				users.push(value.value.name);
			}
		}

		return Response.json({ userNames: users });
	},
} satisfies ExportedHandler;
import { JSONParser } from "@streamparser/json-whatwg";

export default {
	async fetch(request) {
		const parser = new JSONParser({ paths: ["$.users.*"] });

		const users = [];

		// Pipe the request body through the JSON parser
		const reader = request.body
			.pipeThrough(parser)
			.getReader();

		// Process matching JSON values as they stream in
		while (true) {
			const { done, value } = await reader.read();
			if (done) break;
			// Extract only the name field from each user object
			if (value.value?.name) {
				users.push(value.value.name);
			}
		}

		return Response.json({ userNames: users });
	},
};

JSON レスポンスをストリーミングして変換する

この例では、上流 API から大きな JSON レスポンスを取得し、特定のフィールドを変換して、変更後のレスポンスをクライアントへストリーミングします。

import { JSONParser } from "@streamparser/json-whatwg";

export default {
	async fetch(request): Promise<Response> {
		const response = await fetch("https://api.example.com/large-dataset.json");

		const parser = new JSONParser({ paths: ["$.items.*"] });

		const { readable, writable } = new TransformStream();
		const writer = writable.getWriter();
		const encoder = new TextEncoder();

		// Process the upstream response in the background
		(async () => {
			const reader = response.body
				.pipeThrough(parser)
				.getReader();

			await writer.write(encoder.encode('{"processedItems":['));
			let first = true;

			while (true) {
				const { done, value } = await reader.read();
				if (done) break;

				// Transform each item as it streams through
				const item = value.value;
				const transformed = {
					id: item.id,
					title: item.title.toUpperCase(),
					processed: true,
				};

				if (!first) await writer.write(encoder.encode(","));
				first = false;
				await writer.write(encoder.encode(JSON.stringify(transformed)));
			}

			await writer.write(encoder.encode("]}"));
			await writer.close();
		})();

		return new Response(readable, {
			headers: { "Content-Type": "application/json" },
		});
	},
} satisfies ExportedHandler;
import { JSONParser } from "@streamparser/json-whatwg";

export default {
	async fetch(request) {
		const response = await fetch("https://api.example.com/large-dataset.json");

		const parser = new JSONParser({ paths: ["$.items.*"] });

		const { readable, writable } = new TransformStream();
		const writer = writable.getWriter();
		const encoder = new TextEncoder();

		// Process the upstream response in the background
		(async () => {
			const reader = response.body
				.pipeThrough(parser)
				.getReader();

			await writer.write(encoder.encode('{"processedItems":['));
			let first = true;

			while (true) {
				const { done, value } = await reader.read();
				if (done) break;

				// Transform each item as it streams through
				const item = value.value;
				const transformed = {
					id: item.id,
					title: item.title.toUpperCase(),
					processed: true,
				};

				if (!first) await writer.write(encoder.encode(","));
				first = false;
				await writer.write(encoder.encode(JSON.stringify(transformed)));
			}

			await writer.write(encoder.encode("]}"));
			await writer.close();
		})();

		return new Response(readable, {
			headers: { "Content-Type": "application/json" },
		});
	},
};

関連リソース

役に立ちましたか?