L'architettura serverless è diventata uno standard per le moderne applicazioni web, ma gli sviluppatori si trovano regolarmente di fronte a un problema: tutte le richieste dalle funzioni Lambda o dalle Edge Functions provengono da indirizzi IP dei data center dei fornitori di cloud. Questo porta a blocchi quando si accede a API esterne, si esegue il parsing di dati o si automatizzano compiti. In questa guida vedremo come integrare i proxy nelle funzioni serverless per aggirare le limitazioni, i limiti di frequenza e i blocchi geografici.
Perché le funzioni serverless hanno bisogno di proxy
Le piattaforme serverless (AWS Lambda, Google Cloud Functions, Vercel, Cloudflare Workers) eseguono codice nell'infrastruttura cloud, utilizzando indirizzi IP dei data center. Questo crea diversi problemi critici per gli sviluppatori:
Problema 1: Blocchi per IP dei data center. Molti servizi bloccano automaticamente le richieste provenienti da indirizzi IP noti di AWS, Google Cloud o Azure. Ad esempio, durante il parsing di siti di e-commerce (Amazon, eBay, Wildberries) o di social network (Instagram API, TikTok API), le vostre funzioni Lambda riceveranno HTTP 403 o captcha già alla prima richiesta. I sistemi di protezione contro i bot (Cloudflare, Akamai, DataDome) riconoscono immediatamente il traffico proveniente dai data center cloud.
Problema 2: Limitazione della frequenza a livello IP. Se distribuite un'applicazione serverless con migliaia di chiamate simultanee, tutte le richieste possono provenire da uno o più indirizzi IP di AWS. Le API esterne raggiungono rapidamente i limiti (ad esempio, GitHub API — 60 richieste/ora da un IP, Google Maps API — 100 richieste/secondo). Anche se avete pagato un piano API esteso, la limitazione per IP si attiverà comunque.
Problema 3: Blocchi geografici. Le funzioni serverless nella regione us-east-1 non potranno accedere a contenuti disponibili solo dalla Russia, Europa o Asia. Questo è critico durante il parsing di marketplace regionali (Ozon, Yandex.Market), il controllo degli annunci pubblicitari da diversi paesi o il test della localizzazione dei siti.
Problema 4: IP condivisi con altri utenti. Nell'ambiente serverless, le vostre funzioni possono ricevere un indirizzo IP che è già stato utilizzato da altri clienti del fornitore di cloud. Se qualcuno ha abusato di questo IP in precedenza (spam, DDoS, parsing), potrebbe essere nella blacklist. Riceverete un blocco senza alcuna colpa.
La soluzione a tutti questi problemi è l'integrazione di server proxy. I proxy consentono alle vostre funzioni serverless di inviare richieste tramite indirizzi IP residenziali o mobili, che sembrano utenti normali. Questo rimuove i blocchi, aggira i limiti di frequenza e fornisce accesso a contenuti bloccati geograficamente.
Quali tipi di proxy sono adatti per serverless
La scelta del tipo di proxy dipende dall'attività della vostra applicazione serverless. Esaminiamo tre opzioni principali e gli scenari di utilizzo:
| Tipo di proxy | Velocità | Anonimato | Scenari di utilizzo |
|---|---|---|---|
| Proxy dei data center | Molto alta (10-50 ms) | Bassa | Accesso alle API senza restrizioni rigide, verifica della disponibilità dei servizi, monitoraggio dell'uptime |
| Proxy residenziali | Media (100-500 ms) | Alta | Parsing di e-commerce, lavoro con i social media, aggiramento di Cloudflare, accesso a contenuti bloccati geograficamente |
| Proxy mobili | Media (150-600 ms) | Molto alta | Lavoro con API mobili (Instagram, TikTok), test di applicazioni mobili, aggiramento delle protezioni più severe |
Per la maggior parte delle applicazioni serverless è consigliato utilizzare proxy residenziali. Essi offrono un equilibrio ottimale tra velocità e anonimato. Gli IP residenziali sembrano utenti domestici normali, il che consente di aggirare le protezioni contro i bot e i limiti di frequenza senza un significativo aumento della latenza.
I proxy dei data center sono adatti solo per compiti semplici (verifica degli stati HTTP, lavoro con API pubbliche senza restrizioni). I proxy mobili sono necessari in casi specifici — quando si lavora con API mobili o quando è fondamentale avere la massima anonimato.
Configurazione del proxy in AWS Lambda
AWS Lambda è la piattaforma serverless più popolare, e l'integrazione del proxy qui richiede la corretta configurazione del client HTTP. Le funzioni Lambda possono utilizzare diversi linguaggi di programmazione (Node.js, Python, Go), vediamo esempi per i più comuni.
Node.js (axios)
Axios è la libreria più popolare per le richieste HTTP in Node.js. Per configurare il proxy, utilizzare il parametro proxy nella configurazione:
const axios = require('axios');
exports.handler = async (event) => {
const proxyConfig = {
host: 'proxy.example.com',
port: 8080,
auth: {
username: 'your_username',
password: 'your_password'
},
protocol: 'http'
};
try {
const response = await axios.get('https://api.example.com/data', {
proxy: proxyConfig,
timeout: 10000 // 10 secondi
});
return {
statusCode: 200,
body: JSON.stringify(response.data)
};
} catch (error) {
console.error('Errore proxy:', error.message);
return {
statusCode: 500,
body: JSON.stringify({ error: error.message })
};
}
};
Punto importante: memorizzate le credenziali del proxy in AWS Systems Manager Parameter Store o AWS Secrets Manager, e non nel codice. Questo garantirà la sicurezza e consentirà di cambiare facilmente il proxy senza ricompilare la funzione.
Python (requests)
In Python, per lavorare con i proxy si utilizza la libreria requests con il parametro proxies:
import requests
import json
def lambda_handler(event, context):
proxies = {
'http': 'http://username:password@proxy.example.com:8080',
'https': 'http://username:password@proxy.example.com:8080'
}
try:
response = requests.get(
'https://api.example.com/data',
proxies=proxies,
timeout=10
)
return {
'statusCode': 200,
'body': json.dumps(response.json())
}
except requests.exceptions.RequestException as e:
print(f'Errore proxy: {str(e)}')
return {
'statusCode': 500,
'body': json.dumps({'error': str(e)})
}
Per i proxy SOCKS5 (protocollo più sicuro) in Python è necessario installare una libreria aggiuntiva requests[socks] e modificare il formato dell'URL:
proxies = {
'http': 'socks5://username:password@proxy.example.com:1080',
'https': 'socks5://username:password@proxy.example.com:1080'
}
Ottimizzazione per i cold start
Le funzioni Lambda hanno il problema dei cold start: la prima richiesta dopo un periodo di inattività richiede 1-3 secondi. Quando si utilizza un proxy, questo tempo aumenta. Per minimizzare i ritardi, create il client HTTP al di fuori della funzione handler:
const axios = require('axios');
// Creiamo il client una sola volta durante l'inizializzazione del contenitore
const httpClient = axios.create({
proxy: {
host: 'proxy.example.com',
port: 8080,
auth: {
username: process.env.PROXY_USER,
password: process.env.PROXY_PASS
}
},
timeout: 10000
});
exports.handler = async (event) => {
// Riutilizziamo il client ad ogni chiamata
const response = await httpClient.get('https://api.example.com/data');
return {
statusCode: 200,
body: JSON.stringify(response.data)
};
};
Questo approccio riduce il tempo di cold start di 200-500 ms, poiché la configurazione del proxy viene eseguita solo una volta durante la creazione del contenitore Lambda.
Integrazione del proxy nelle Vercel Edge Functions
Vercel offre due tipi di funzioni serverless: Node.js Functions (analoghe a Lambda) e Edge Functions (eseguite su CDN). Le Edge Functions operano in un runtime simile a Cloudflare Workers, con limitazioni sull'uso delle API di Node.js. Esaminiamo entrambe le opzioni.
Vercel Node.js Functions
Per le normali Vercel Functions utilizzate lo stesso approccio di AWS Lambda. Create un file api/fetch-data.js:
import axios from 'axios';
export default async function handler(req, res) {
const proxyConfig = {
host: process.env.PROXY_HOST,
port: parseInt(process.env.PROXY_PORT),
auth: {
username: process.env.PROXY_USER,
password: process.env.PROXY_PASS
}
};
try {
const response = await axios.get(req.query.url, {
proxy: proxyConfig,
timeout: 8000
});
res.status(200).json(response.data);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
Aggiungete le variabili d'ambiente nel Vercel Dashboard (Impostazioni → Variabili d'ambiente): PROXY_HOST, PROXY_PORT, PROXY_USER, PROXY_PASS.
Vercel Edge Functions
Le Edge Functions utilizzano l'API Web Fetch invece delle librerie Node.js. Il proxy viene configurato tramite intestazioni personalizzate o middleware:
export const config = {
runtime: 'edge',
};
export default async function handler(req) {
const proxyUrl = `http://${process.env.PROXY_USER}:${process.env.PROXY_PASS}@${process.env.PROXY_HOST}:${process.env.PROXY_PORT}`;
// Per Edge Runtime è necessario fetch con proxy tramite agent (richiede polyfill)
// Alternativa: utilizzare direttamente l'API proxy
const targetUrl = new URL(req.url).searchParams.get('target');
const response = await fetch(targetUrl, {
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
});
return new Response(await response.text(), {
status: response.status,
headers: response.headers
});
}
Importante limitazione: Edge Runtime non supporta gli agenti proxy standard di Node.js. Per un funzionamento completo con i proxy è consigliabile utilizzare le Node.js Functions o creare un server proxy intermedio su un server separato, che accetterà le richieste dalle Edge Functions.
Proxy in Cloudflare Workers
Cloudflare Workers operano in V8 isolates e hanno restrizioni ancora più severe rispetto alle Vercel Edge Functions. Il metodo standard per collegare un proxy tramite librerie Node.js qui non funziona. Ci sono due approcci funzionanti:
Metodo 1: Tunneling HTTP CONNECT
Utilizzate un proxy che supporta il metodo HTTP CONNECT. Create un tunnel attraverso il server proxy:
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
const proxyUrl = 'http://proxy.example.com:8080';
const targetUrl = 'https://api.example.com/data';
const proxyAuth = btoa(`${PROXY_USER}:${PROXY_PASS}`);
const response = await fetch(proxyUrl, {
method: 'CONNECT',
headers: {
'Host': new URL(targetUrl).host,
'Proxy-Authorization': `Basic ${proxyAuth}`
}
});
if (response.status === 200) {
// Tunnel stabilito, eseguiamo la richiesta principale
const finalResponse = await fetch(targetUrl, {
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
}
});
return finalResponse;
}
return new Response('Connessione proxy fallita', { status: 502 });
}
Questo metodo funziona solo con proxy HTTP che supportano CONNECT. La maggior parte dei fornitori di proxy residenziali offre questa possibilità.
Metodo 2: Proxy Gateway (raccomandato)
Un modo più affidabile è distribuire un proxy gateway intermedio su un server separato (ad esempio, su VPS o AWS EC2). Cloudflare Worker invia richieste al vostro gateway, che poi le inoltra tramite il proxy:
// Cloudflare Worker
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
const targetUrl = new URL(request.url).searchParams.get('url');
const gatewayUrl = 'https://your-proxy-gateway.com/fetch';
const response = await fetch(gatewayUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': API_KEY // Protezione del vostro gateway
},
body: JSON.stringify({
url: targetUrl,
method: 'GET'
})
});
return response;
}
Dalla parte del proxy gateway (server Node.js):
const express = require('express');
const axios = require('axios');
const app = express();
app.use(express.json());
const proxyConfig = {
host: 'proxy.example.com',
port: 8080,
auth: {
username: process.env.PROXY_USER,
password: process.env.PROXY_PASS
}
};
app.post('/fetch', async (req, res) => {
if (req.headers['x-api-key'] !== process.env.API_KEY) {
return res.status(401).json({ error: 'Non autorizzato' });
}
try {
const response = await axios({
url: req.body.url,
method: req.body.method || 'GET',
proxy: proxyConfig,
timeout: 10000
});
res.json(response.data);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(3000);
Questo approccio aggiunge un ulteriore hop (aumento della latenza di 50-100 ms), ma garantisce piena compatibilità e controllo sulla connessione proxy.
Rotazione degli indirizzi IP nell'ambiente serverless
Una delle principali ragioni per utilizzare i proxy è distribuire le richieste tra molti indirizzi IP per aggirare i limiti di frequenza. Nell'architettura serverless ci sono due approcci alla rotazione:
Rotazione automatica dal lato del fornitore di proxy
La maggior parte dei fornitori di proxy residenziali offre proxy rotanti: ci si connette a un endpoint e l'IP cambia automaticamente ad ogni richiesta o attraverso un intervallo impostato (ad esempio, ogni 5 minuti). Questa è l'opzione più semplice per serverless:
// Un endpoint, l'IP cambia automaticamente
const proxyConfig = {
host: 'rotating.proxy.example.com',
port: 8080,
auth: {
username: 'user-session-' + Date.now(), // Sessione unica
password: 'password'
}
};
Alcuni fornitori consentono di gestire la rotazione tramite parametri nel nome utente: user-session-random (nuovo IP ad ogni richiesta), user-session-sticky-300 (un IP per 300 secondi).
Rotazione manuale tramite pool di proxy
Se avete un elenco di proxy statici (ad esempio, avete acquistato proxy dedicati), potete implementare la rotazione a livello di applicazione. Nell'ambiente serverless utilizzate DynamoDB (AWS) o KV Storage (Cloudflare) per memorizzare lo stato:
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB.DocumentClient();
const PROXY_POOL = [
{ host: 'proxy1.example.com', port: 8080 },
{ host: 'proxy2.example.com', port: 8080 },
{ host: 'proxy3.example.com', port: 8080 }
];
async function getNextProxy() {
// Otteniamo l'indice corrente da DynamoDB
const result = await dynamodb.get({
TableName: 'ProxyRotation',
Key: { id: 'current_index' }
}).promise();
const currentIndex = result.Item?.index || 0;
const nextIndex = (currentIndex + 1) % PROXY_POOL.length;
// Aggiorniamo l'indice
await dynamodb.put({
TableName: 'ProxyRotation',
Item: { id: 'current_index', index: nextIndex }
}).promise();
return PROXY_POOL[currentIndex];
}
exports.handler = async (event) => {
const proxy = await getNextProxy();
const response = await axios.get('https://api.example.com/data', {
proxy: {
...proxy,
auth: {
username: process.env.PROXY_USER,
password: process.env.PROXY_PASS
}
}
});
return { statusCode: 200, body: JSON.stringify(response.data) };
};
Questo metodo offre pieno controllo sulla rotazione, ma richiede richieste aggiuntive a DynamoDB (aumenta la latenza di 10-30 ms). Per applicazioni ad alto carico, è consigliabile memorizzare l'indice nella memoria del contenitore Lambda e aggiornarlo ogni 100-1000 richieste.
Gestione degli errori e dei timeout
I proxy aggiungono un ulteriore punto di errore alla vostra applicazione serverless. È fondamentale gestire correttamente gli errori per non perdere le richieste degli utenti.
Errori comuni durante l'uso dei proxy
| Errore | Causa | Soluzione |
|---|---|---|
| ETIMEDOUT | Il proxy non risponde o è lento | Riducete il timeout a 5-8 secondi, aggiungete un retry con un altro proxy |
| ECONNREFUSED | Il server proxy non è disponibile | Controllate la disponibilità del proxy, utilizzate un fallback su un altro proxy |
| 407 Proxy Authentication Required | Credenziali errate | Controllate username/password, assicuratevi che l'IP Lambda sia autorizzato nella whitelist del proxy |
| 502 Bad Gateway | Il proxy non riesce a connettersi al sito di destinazione | Il sito potrebbe bloccare il proxy, provate un altro IP o tipo di proxy |
Implementazione della logica di retry con fallback
Aggiungete tentativi automatici con switch su un proxy di riserva in caso di errori:
const axios = require('axios');
const PRIMARY_PROXY = {
host: 'primary.proxy.com',
port: 8080,
auth: { username: 'user', password: 'pass' }
};
const FALLBACK_PROXY = {
host: 'fallback.proxy.com',
port: 8080,
auth: { username: 'user', password: 'pass' }
};
async function fetchWithRetry(url, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const proxy = attempt === 0 ? PRIMARY_PROXY : FALLBACK_PROXY;
try {
const response = await axios.get(url, {
proxy,
timeout: 8000
});
return response.data;
} catch (error) {
console.log(`Tentativo ${attempt + 1} fallito:`, error.message);
// Non retry su errori client (4xx)
if (error.response && error.response.status < 500) {
throw error;
}
// Ultimo tentativo — rilancia l'errore
if (attempt === maxRetries - 1) {
throw error;
}
// Ritardo esponenziale prima del retry
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt)));
}
}
}
exports.handler = async (event) => {
try {
const data = await fetchWithRetry('https://api.example.com/data');
return { statusCode: 200, body: JSON.stringify(data) };
} catch (error) {
return { statusCode: 500, body: JSON.stringify({ error: error.message }) };
}
};
Questa implementazione offre tre tentativi di richiesta: il primo tramite il proxy principale, gli altri tramite quello di riserva. Tra i tentativi è stato aggiunto un ritardo esponenziale (1 sec, 2 sec, 4 sec) per non creare carico eccessivo.
Monitoraggio e avvisi
Configurate il monitoraggio degli errori del proxy tramite CloudWatch (AWS), Vercel Analytics o Sentry. Monitorate le metriche:
- Percentuale di richieste riuscite tramite proxy (dovrebbe essere >95%)
- Latenza media delle richieste (un aumento può indicare problemi con il proxy)
- Numero di errori di timeout (se >5% — il proxy è sovraccarico o lento)
- Distribuzione degli errori per codice (407, 502, ETIMEDOUT, ecc.)
Configurate avvisi al superamento delle soglie — questo consentirà di passare rapidamente a un fornitore di proxy di riserva o di modificare la configurazione.
Conclusione
L'integrazione dei proxy nelle applicazioni serverless risolve problemi critici: blocchi per IP dei data center, limitazioni di frequenza e blocchi geografici. Abbiamo esaminato la configurazione dei proxy in AWS Lambda (Node.js e Python), Vercel Functions e Cloudflare Workers, nonché l'implementazione della rotazione degli indirizzi IP e la gestione degli errori.
Raccomandazioni chiave: utilizzate proxy residenziali per attività che richiedono alta anonimato (parsing, lavoro con API dei social media), memorizzate le credenziali in archivi sicuri (AWS Secrets Manager, Vercel Environment Variables), implementate la logica di retry con fallback su proxy di riserva e configurate il monitoraggio degli errori.
Per applicazioni serverless con elevate esigenze di stabilità, raccomandiamo di utilizzare proxy residenziali con rotazione automatica — essi offrono un equilibrio ottimale tra velocità, anonimato e affidabilità, minimizzando il rischio di blocchi durante l'interazione con API e servizi esterni.