INTEGRITY Документация

Маршрутизация запросов между различными веб-серверами

Использование Workers KV для хранения данных маршрутизации и распределения запросов между разными веб-серверами с помощью Workers является идеальным сценарием использования Workers KV. Такая нагрузка на маршрутизацию может создавать высокий объём операций чтения, и быстрые операции чтения Workers KV с низкой задержкой помогают принимать решения о маршрутизации быстро и эффективно.

Маршрутизация полезна, когда нужно направлять запросы, поступающие в одно приложение Cloudflare Worker, на разные веб-серверы в зависимости от пути запроса, хоста или других его атрибутов.

В однотенантных приложениях это можно использовать для маршрутизации запросов к разным серверам источника в зависимости от бизнес-домена (например, запросы к /admin направляется на административный сервер, /store направляется на сервер витрины, /api направляется на сервер API).

В мультитенантных приложениях запросы можно направлять к соответствующим ресурсам источника конкретного тенанта (например, запросы к tenantA.your-worker-hostname.com направляется на сервер для Tenant A, tenantB.your-worker-hostname.com направляется на сервер для Tenant B).

Маршрутизацию также можно использовать для реализации A/B тестирование, canary-развертывания, или сине-зелёные развёртывания ↗ для собственных внешних приложений. Если вы хотите реализовать canary или blue-green развёртывания приложений, полностью построенных на Cloudflare Workers, см. Workers gradual deployments.

Маршрутизация запросов с помощью Workers KV

В этом примере на Cloudflare Workers построено мультитенантное приложение электронной коммерции. Каждый интернет-магазин представляет собой отдельного тенанта и имеет собственный внешний веб-сервер. Наш Cloudflare Worker принимает все запросы для всех магазинов и направляет их на нужный веб-сервер источника в соответствии с идентификатором магазина.

Для простоты демонстрации витрина магазина будет идентифицироваться с помощью элемента пути, содержащего ID витрины, где https://<WORKER_HOSTNAME>/<STOREFRONT_ID>/... это шаблон URL для витрины. В реальном сценарии вам может быть удобнее использовать поддомены для идентификации витрин.

index.ts

// Example routing data stored in Workers KV:
// Key: "storefrontA" | Value: {"origin": "https://storefrontA-server.example.com"}
// Key: "storefrontB" | Value: {"origin": "https://storefrontB-server.example.com"}

interface Env {
ROUTING_CONFIG: KVNamespace;
}

export default {
  async fetch(request, env, ctx) {

    // Parse the URL to extract the storefront ID from the path
    const url = new URL(request.url);
    const pathParts = url.pathname.split('/').filter(part => part !== '');

    // Check if a storefront ID is provided in the path, otherwise return 400
    if (pathParts.length === 0) {
      return new Response('Welcome to our multi-tenant platform. Please specify a storefront ID in the URL path.', {
        status: 400,
        headers: { 'Content-Type': 'text/plain' }
      });
    }

    // Extract the storefront ID from the first path segment
    const storefrontId = pathParts[0];

    try {
      // Look up the storefront configuration in KV using env.ROUTING_CONFIG
      const storefrontConfig = await env.ROUTING_CONFIG.get<{
    			origin: string;
    		}>(storefrontId, {type: "json"});

      // If no configuration is found, return a 404
      if (!storefrontConfig) {
        return new Response(`Storefront "${storefrontId}" not found.`, {
          status: 404,
          headers: { 'Content-Type': 'text/plain' }
        });
      }

      // Construct the new URL for the origin server
      // Remove the storefront ID from the path when forwarding
      const newPathname = '/' + pathParts.slice(1).join('/');
      const originUrl = new URL(newPathname, storefrontConfig.origin);
      originUrl.search = url.search;

      // Create a new request to the origin server
      const originRequest = new Request(originUrl, {
        method: request.method,
        headers: request.headers,
        body: request.body,
        redirect: 'follow'
      });

      // Send the request to the origin server
      const response = await fetch(originRequest);

    		console.log(response.status)

      // Clone the response and add a custom header
      const modifiedResponse = new Response(response.body, response);
      modifiedResponse.headers.set('X-Served-By', 'Cloudflare Worker');
      modifiedResponse.headers.set('X-Storefront-ID', storefrontId);

      return modifiedResponse;

    } catch (error) {
      // Handle any errors
      console.error(`Error processing request for storefront ${storefrontId}:`, error);
      return new Response('An error occurred while processing your request.', {
        status: 500,
        headers: { 'Content-Type': 'text/plain' }
      });
    }

}
} satisfies ExportedHandler<Env>;
{
	"$schema": "node_modules/wrangler/config-schema.json",
	"name": "<ENTER_WORKER_NAME>",
	"main": "src/index.ts",
	"compatibility_date": "2025-03-03",
	"observability": {
		"enabled": true
	},
	"kv_namespaces": [
		{
			"binding": "ROUTING_CONFIG",
			"id": "<YOUR_BINDING_ID>"
		}
	]
}

В этом примере Cloudflare Worker принимает запрос и извлекает идентификатор магазина из пути URL. Этот идентификатор используется для поиска URL-адреса сервера источника в Workers KV с помощью get() метод. Затем запрос перенаправляется на исходный сервер, а в ответ перед возвратом клиенту добавляются пользовательские заголовки.