INTEGRITY Dokumentace

Směrování požadavků mezi různými webovými servery

Použití Workers KV k ukládání směrovacích dat pro směrování požadavků mezi různými webovými servery pomocí Workers je ideálním případem použití pro Workers KV. Směrovací úlohy mohou mít vysoký objem čtení a nízká latence čtení ve Workers KV pomáhá zajistit, aby se směrovací rozhodnutí prováděla rychle a efektivně.

Směrování je užitečné pro přesměrování požadavků přicházejících do jedné aplikace Cloudflare Worker na různé webové servery na základě cesty požadavku, hostname nebo dalších atributů požadavku.

V jednotenantních aplikacích to lze použít ke směrování požadavků na různé zdrojové servery podle obchodní domény (například požadavky na /admin směrován na administrační server, /store směrován na server obchodu, /api směrován na API server).

V multitenantních aplikacích lze požadavky směrovat na příslušné zdrojové prostředky daného tenanta (například požadavky na tenantA.your-worker-hostname.com směrován na server pro Tenant A, tenantB.your-worker-hostname.com směrován na server pro Tenant B).

Směrování lze také použít k implementaci A/B testování, canary nasazení nebo blue-green nasazení ↗ pro vaše vlastní externí aplikace. Pokud chcete implementovat canary nebo blue-green nasazení aplikací postavených výhradně na Cloudflare Workers, viz Workers gradual deployments.

Směrování požadavků pomocí Workers KV

V tomto příkladu je na Cloudflare Workers postavena multitenantní e-commerce aplikace. Každý obchod představuje samostatného tenanta a má svůj vlastní externí webový server. Náš Cloudflare Worker přijímá všechny požadavky pro všechny obchody a směruje je na správný zdrojový webový server podle ID obchodu.

Pro zjednodušení ukázky bude obchod identifikován pomocí prvku cesty obsahujícího ID obchodu, kde https://<WORKER_HOSTNAME>/<STOREFRONT_ID>/... je vzor URL adresy pro obchod. V reálném nasazení byste pro identifikaci jednotlivých obchodů pravděpodobně raději použili subdomény.

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>"
		}
	]
}

V tomto příkladu Cloudflare Worker přijme požadavek a z cesty URL extrahuje ID obchodu. Toto ID obchodu se použije k vyhledání URL zdrojového serveru ve Workers KV pomocí get() metoda. Požadavek je poté předán na origin server a odpověď je před vrácením klientovi upravena tak, aby obsahovala vlastní hlavičky.