Routing geograficzny na krawędzi: personalizacja treści i zgodność z RODO
Naucz się budować logikę routingu w oparciu o kraj, region i język bezpośrednio u Pracowników, z przykładami geofencingu, zlokalizowanymi cenami i zgodność z RODO bez zmiany głównego serwera.
Dlaczego routing geograficzny należy do krawędzi
Personalizacja treści na podstawie lokalizacji geograficznej jest jednym z nich najczęstsze potrzeby w globalnych aplikacjach internetowych: wyświetlanie cen w walucie lokalnej, przestrzegać przepisów obowiązujących w danym kraju (RODO w Europie, CCPA w Kalifornii), blokowanie treści w niektórych jurysdykcjach i przekierowywanie w kierunku domen regionalnych.
Historycznie rzecz biorąc, obsługiwano to za pomocą baz danych geolokalizacji po stronie serwera (MaxMind GeoLite2) lub z ręcznie skonfigurowanymi regułami CDN. Obydwa podejścia mają ograniczenia: serwer bazy danych dodaje opóźnienia, reguły CDN są statyczne i trudne do dynamicznej aktualizacji.
W przypadku Cloudflare Workers geolokalizacja jest już dostępne
w obiekcie request.cf bez żadnej bazy danych do utrzymania.
Cloudflare określa lokalizację na podstawie topologii BGP sieci,
nie podczas wyszukiwania adresów IP, z dokładnością na poziomie kraju powyżej 99,9%.
Czego się nauczysz
- Nieruchomości dostępne w
request.cfdo geolokalizacji - Geo-fencing: blokowanie i przekierowywanie według kraju
- Ceny lokalne: waluta i podatek VAT w zależności od regionu
- Zgodność z RODO: automatyczna zgoda na pliki cookie dla użytkowników z UE
- Routing wieloregionowy z niestandardowymi nagłówkami
- Testowanie logiki opartej na lokalizacji geograficznej bez wdrażania
Obiekt request.cf przez Cloudflare
Każde żądanie skierowane do pracownika Cloudflare zawiera temat cf z
Metadane geograficzne i sieciowe ustalane przez Cloudflare w czasie rzeczywistym:
// Tutte le proprieta disponibili in request.cf
export default {
async fetch(request: Request): Promise<Response> {
const cf = request.cf as CfProperties;
// Geolocalizzazione
const country = cf.country; // "IT" - ISO 3166-1 alpha-2
const region = cf.region; // "Puglia" - nome della regione
const regionCode = cf.regionCode; // "75" - codice regione
const city = cf.city; // "Bari"
const postalCode = cf.postalCode; // "70121"
const latitude = cf.latitude; // "41.1171"
const longitude = cf.longitude; // "16.8719"
const timezone = cf.timezone; // "Europe/Rome"
const continent = cf.continent; // "EU"
// Rete
const asn = cf.asn; // 1234 - Autonomous System Number
const asOrganization = cf.asOrganization; // "Telecom Italia"
const isEuCountry = cf.isEUCountry; // "1" o "0"
// Performance
const colo = cf.colo; // "FCO" - datacenter Cloudflare piu vicino
const httpProtocol = cf.httpProtocol; // "HTTP/2"
const tlsVersion = cf.tlsVersion; // "TLSv1.3"
return Response.json({
country,
region,
city,
timezone,
continent,
isEuCountry,
colo,
});
},
};
// Tipo per le proprieta cf (parziale)
interface CfProperties {
country?: string;
region?: string;
regionCode?: string;
city?: string;
postalCode?: string;
latitude?: string;
longitude?: string;
timezone?: string;
continent?: string;
asn?: number;
asOrganization?: string;
isEUCountry?: string;
colo?: string;
httpProtocol?: string;
tlsVersion?: string;
}
Geo-ogrodzenie: blokowanie według kraju
Geo-ogrodzenie to wzorzec blokowania lub przekierowywania treści do określonych odbiorców kraje. Najczęstsze przypadki użycia to: blokowanie ze względu na sankcje międzynarodowe, treści z licencjami terytorialnymi (streaming, media), a rynki jeszcze nie otwarty na niektóre produkty:
// src/geo-fence-worker.ts
// Paesi con accesso bloccato (esempio: sanzioni, licenze)
const BLOCKED_COUNTRIES = new Set(['KP', 'IR', 'SY', 'CU']);
// Paesi che richiedono un redirect a una versione localizzata
const REDIRECTS: Record<string, string> = {
DE: 'https://de.example.com',
FR: 'https://fr.example.com',
JP: 'https://jp.example.com',
};
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const cf = request.cf as CfProperties;
const country = cf.country ?? 'US';
const url = new URL(request.url);
// Blocco per paesi non consentiti
if (BLOCKED_COUNTRIES.has(country)) {
return new Response(
JSON.stringify({
error: 'Service not available in your region',
country,
}),
{
status: 451, // 451 Unavailable For Legal Reasons
headers: {
'Content-Type': 'application/json',
'Vary': 'CF-IPCountry',
},
}
);
}
// Redirect verso versione localizzata per certi paesi
const redirectTarget = REDIRECTS[country];
if (redirectTarget && !url.pathname.startsWith('/api/')) {
const targetUrl = new URL(url.pathname + url.search, redirectTarget);
return Response.redirect(targetUrl.toString(), 302);
}
// Aggiunge header con il paese per il downstream (server di origine)
const headers = new Headers(request.headers);
headers.set('CF-Worker-Country', country);
headers.set('CF-Worker-Continent', cf.continent ?? '');
headers.set('CF-Worker-Timezone', cf.timezone ?? '');
// Prosegui verso il server di origine
return fetch(new Request(request.url, {
method: request.method,
headers,
body: ['GET', 'HEAD'].includes(request.method) ? undefined : request.body,
}));
},
};
interface CfProperties {
country?: string;
continent?: string;
timezone?: string;
}
interface Env {}
Zlokalizowane ceny i waluty
Pokazywanie cen w lokalnej walucie klienta jest najlepszą praktyką e-commerce, co zwiększa współczynnik konwersji. Dzięki Workerowi możesz określić właściwą walutę, zanim żądanie dotrze serwer pochodzenia:
// src/pricing-worker.ts - prezzi localizzati all'edge
interface CurrencyConfig {
code: string;
symbol: string;
position: 'before' | 'after';
vatRate: number; // IVA in percentuale (0.22 = 22%)
}
const COUNTRY_CURRENCY: Record<string, CurrencyConfig> = {
// Eurozona
IT: { code: 'EUR', symbol: '€', position: 'before', vatRate: 0.22 },
DE: { code: 'EUR', symbol: '€', position: 'before', vatRate: 0.19 },
FR: { code: 'EUR', symbol: '€', position: 'before', vatRate: 0.20 },
ES: { code: 'EUR', symbol: '€', position: 'before', vatRate: 0.21 },
// Altre valute
GB: { code: 'GBP', symbol: '£', position: 'before', vatRate: 0.20 },
US: { code: 'USD', symbol: '






