Migrando padrões de handler em Functions

As Azion Functions suportam dois padrões de handler: ES Modules (recomendado) e Service Worker (legado). Este guia explica as diferenças entre eles e como migrar suas functions existentes para o padrão ES Modules.

Padrões suportados

ES Modules (recomendado)

O padrão ES Modules é a forma recomendada de estruturar suas functions na Azion. Ele oferece uma sintaxe moderna e limpa, com suporte nativo em produção e melhor desempenho.

export default {
fetch: (request, env, ctx) => {
return new Response('Hello World');
},
firewall: (request, env, ctx) => {
// Lógica de firewall
ctx.deny();
}
};

Service Worker (legado)

O padrão Service Worker é mantido para compatibilidade com código legado. Se você estiver usando esse padrão, a Azion recomenda migrar para ES Modules.

addEventListener('fetch', (event) => {
event.respondWith(handleRequest(event.request));
});
addEventListener('firewall', (event) => {
// Lógica de firewall
event.deny();
});
async function handleRequest(request) {
return new Response('Hello World');
}

Parâmetros dos handlers

fetch(request, env, ctx)

ParâmetroTipoDescrição
requestRequestO objeto da requisição HTTP recebida
envObjectVariáveis de ambiente e bindings
ctxObjectContexto de execução. Use ctx.waitUntil(promise) para estender o tempo de vida da function para tarefas assíncronas

firewall(request, env, ctx) — ES Modules

ParâmetroTipoDescrição
requestRequestO objeto da requisição HTTP recebida
envObjectVariáveis de ambiente e bindings
ctxObjectContexto de execução. Chame ctx.deny() para bloquear a requisição imediatamente. Se ctx.deny() não for chamado, a requisição continua para o handler fetch

Evento de firewall — Service Worker

PropriedadeDescrição
event.requestAcesso ao objeto Request
event.deny()Bloqueia a requisição imediatamente. Se não for chamado, a requisição continua para o handler fetch

Migrando de Service Worker para ES Modules

Handler fetch básico

Antes (Service Worker):

addEventListener('fetch', (event) => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const url = new URL(request.url);
if (url.pathname === '/api/hello') {
return new Response(JSON.stringify({ message: 'Hello World' }), {
headers: { 'Content-Type': 'application/json' }
});
}
return new Response('Not Found', { status: 404 });
}

Depois (ES Modules):

export default {
fetch: async (request, env, ctx) => {
const url = new URL(request.url);
if (url.pathname === '/api/hello') {
return new Response(JSON.stringify({ message: 'Hello World' }), {
headers: { 'Content-Type': 'application/json' }
});
}
return new Response('Not Found', { status: 404 });
}
};

Handler firewall

Antes (Service Worker):

addEventListener('fetch', (event) => {
event.respondWith(handleRequest(event.request));
});
addEventListener('firewall', (event) => {
const clientIP = event.request.headers.get('X-Forwarded-For');
const userAgent = event.request.headers.get('User-Agent');
// Bloquear requisições de bots
if (userAgent && userAgent.includes('bot')) {
event.deny();
return;
}
// Bloquear IPs específicos
if (clientIP === '192.168.1.100') {
event.deny();
return;
}
// Permitir que a requisição continue para o handler fetch
});
async function handleRequest(request) {
return new Response('Hello World');
}

Depois (ES Modules):

export default {
fetch: async (request, env, ctx) => {
return new Response('Acesso concedido');
},
firewall: async (request, env, ctx) => {
const clientIP = request.headers.get('X-Forwarded-For');
const userAgent = request.headers.get('User-Agent');
// Bloquear requisições de bots
if (userAgent && userAgent.includes('bot')) {
ctx.deny();
return;
}
// Bloquear IPs específicos
if (clientIP === '192.168.1.100') {
ctx.deny();
return;
}
// Permitir que a requisição continue para o handler fetch
return;
}
};

Usando waitUntil para tarefas assíncronas

export default {
fetch: async (request, env, ctx) => {
// Use waitUntil para tarefas assíncronas que não devem bloquear a resposta
ctx.waitUntil(logRequest(request));
return new Response('Hello World');
}
};
async function logRequest(request) {
console.log(`Requisição para: ${request.url}`);
}

Firewall avançado com regras baseadas em path

export default {
fetch: async (request, env, ctx) => {
return new Response('Acesso concedido');
},
firewall: async (request, env, ctx) => {
const url = new URL(request.url);
const userAgent = request.headers.get('User-Agent');
const clientIP = request.headers.get('X-Forwarded-For');
// Bloquear requisições de bots
if (userAgent && userAgent.includes('bot')) {
ctx.deny();
return;
}
// Restringir acesso a paths de admin por faixa de IP
if (url.pathname.startsWith('/admin')) {
if (!clientIP || !clientIP.startsWith('192.168.')) {
ctx.deny();
return;
}
}
// Permitir que a requisição continue para o handler fetch
return;
}
};

Padrões não suportados

Os seguintes padrões não são suportados pelas Azion Functions. Se o seu código utilizar algum deles, migre para o padrão ES Modules.

// ❌ Export direto de função
export default function(request) {
return new Response('Hello');
}
// ❌ Named exports
export function fetch(request) {
return new Response('Hello');
}
// ❌ Sem export
function handleRequest(request) {
return new Response('Hello');
}

Solução de problemas

”Unsupported handler pattern detected”

Esse erro aparece quando o código não segue nenhum dos padrões suportados. Para resolver, migre para o padrão ES Modules:

export default {
fetch: async (request, env, ctx) => {
return new Response('Hello World');
}
};

Como alternativa temporária, use o padrão Service Worker:

addEventListener('fetch', (event) => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
return new Response('Hello World');
}

Recursos relacionados