Rutarea geografică la margine: personalizarea conținutului și conformitatea cu GDPR
Învață să construiești o logică de rutare bazată pe țară, regiune și limbă direct în Muncitori, cu exemple de geo-împrejmuire, prețuri localizate și conformitatea cu GDPR fără a schimba serverul principal.
De ce rutarea geografică aparține marginii
Personalizarea conținutului în funcție de locația geografică este una dintre cele mai importante cele mai comune nevoi în aplicațiile web globale: afișarea prețurilor în moneda locală, respectă reglementările specifice țării (GDPR în Europa, CCPA în California), blocați conținut în anumite jurisdicții și redirecționați spre domenii regionale.
Din punct de vedere istoric, acest lucru a fost gestionat cu baze de date de geolocalizare pe partea de server (MaxMind GeoLite2) sau cu reguli CDN configurate manual. Ambele abordări au limitări: serverul de baze de date adaugă latență, regulile CDN sunt statice și dificil de actualizat dinamic.
Cu Cloudflare Workers, geolocalizarea este deja disponibile
în obiect request.cf fără nicio bază de date de întreținut.
Cloudflare determină locația pe baza topologiei BGP a rețelei,
nu pe căutarea IP, cu precizie la nivel de țară peste 99,9%.
Ce vei învăța
- Proprietăți disponibile în
request.cfpentru geolocalizare - Geo-fencing: blocare și redirecționare în funcție de țară
- Prețuri localizate: monedă și TVA în funcție de regiune
- Conformitate GDPR: consimțământ automat pentru cookie-uri pentru utilizatorii din UE
- Rutare în mai multe regiuni cu anteturi personalizate
- Testarea logicii bazate pe geometrie fără implementare
Obiectul request.cf de Cloudflare
Fiecare cerere către un lucrător Cloudflare include subiectul cf cu
Metadate geografice și de rețea determinate de Cloudflare în timp real:
// 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-Fencing: blocare în funcție de țară
Geo-fencing este modelul de blocare sau redirecționare a conținutului către anumite ţări. Cele mai frecvente cazuri de utilizare sunt: blocarea pentru sancțiuni internaționale, conținut cu licențe teritoriale (streaming, media) și piețe care nu sunt încă deschis pentru anumite produse:
// 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 {}
Prețuri și valute localizate
Afișarea prețurilor în moneda locală a clientului este cea mai bună practică a comerțului electronic care crește rata de conversie. Cu Muncitorul, poți determinați moneda corectă înainte ca cererea să ajungă serverul de origine:
// 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: '






