Filtros de solicitação HTTP com funções Edge

IMPORTANT
O AEM Edge Functions está atualmente na versão beta. Os recursos e a documentação podem mudar. Para receber comentários, contate aemcs-edgecompute-feedback@adobe.com.

Saiba como implementar a filtragem de solicitações HTTP com o AEM Edge Functions para regravar ou redirecionar solicitações ou modificar respostas HTTP.

Quando filtrar solicitações HTTP com funções Edge

Uma função Edge do AEM pode agir como um proxy reverso que executa o processamento avançado na solicitação e resposta antes que eles alcancem a origem ou o cliente.

Os dois cenários são:

Ajustar a solicitação antes que ela atinja a origem

Interceptar o tráfego no caminho para a origem para:

  • Reescreva a origem, o caminho ou a consulta da solicitação. Rotear a solicitação para um back-end, caminho ou sequência de consulta diferente para que a origem receba o recurso correto.
  • Reescrever cabeçalhos de solicitação. Adicione, remova ou modifique cabeçalhos antes que a solicitação atinja a origem. Por exemplo, adicione uma geografia ou cabeçalho de acesso que a origem espera, remova cabeçalhos que a origem ignora ou altere um valor de cabeçalho para alterar o comportamento da solicitação.

Modificar a resposta antes que ela chegue ao cliente

Interceptar o tráfego no caminho de volta para o cliente (visitante) para:

  • Alterar a HTML de resposta. Insira JavaScript, conteúdo personalizado, reescreva links ou compile em um cabeçalho e rodapé antes que a página chegue ao navegador.
  • Redirecionar na borda. Atender a um grande conjunto de redirecionamentos de URL herdados para novos da CDN, especialmente quando as regras de redirecionamento exigem lógica programática.
  • Personalizar por contexto de solicitação. Varie uma página ou seção de uma página por geolocalização, dispositivo ou público-alvo para visitantes públicos. Isso se aplica ao tráfego de publicação no domínio do site, não ao tráfego de criação.

Implementar a filtragem de solicitação HTTP

A filtragem de solicitação HTTP usa dois arquivos. O arquivo config/cdn.yaml decide qual tráfego interceptar e rotear para sua Função Edge do AEM. O arquivo src/index.js executa o ajuste de solicitação ou resposta.

O seletor de origem e o nome da função devem ser alinhados. Se edgeFunctions.yaml declara my-edge-function, o seletor de origem usa edgefunction-my-edge-function em cdn.yaml.

Configurar o filtro CDN

# config/cdn.yaml (origin selector excerpt)
kind: "CDN"
version: "1"
data:
  originSelectors:
    rules:
      - name: route-to-edge-function
        when:
          allOf:
            - { reqProperty: tier, equals: "publish" } # publish traffic only; skip author
            - { reqProperty: domain, equals: "www.example.com" } # your site hostname
            - { reqProperty: originalPath, matches: "(/[^./]+|\\.html|/)$" } # page URLs; skip static assets (.css, .js, images, fonts)
            # - { reqProperty: method, in: ["GET", "HEAD"] } # optional: navigation only; skip POST, PUT, and other methods with bodies
            - { reqHeader: x-edgefunction-request, exists: false } # skip loopback requests to prevent infinite loops
        action:
          type: selectAemOrigin
          originName: edgefunction-my-edge-function # edgefunction-<name-of-the-function>

Se qualquer condição falhar, a solicitação nunca atingirá a Função Edge do AEM. Comece com o mínimo de condições que sua função precisa e adicione mais apenas para tornar o roteamento mais preciso. Para todas as propriedades e operadores compatíveis, consulte Seletores de origem.

Implementar o manipulador

Cada função do AEM Edge registra um manipulador de eventos de busca. Use o manipulador para ajustar a solicitação antes que ela atinja a origem, modifique a resposta antes que ela atinja o cliente ou ambos.

O trecho de código a seguir demonstra a filtragem de solicitações e a modificação de resposta em uma função Edge do AEM.

// src/index.js
addEventListener("fetch", (event) => event.respondWith(handleRequest(event)));

async function handleRequest(event) {
  const req = event.request;
  const url = new URL(req.url);

  try {
    // ------------------------------------------------------------
    // --- Request filtering: adjust before origin ---
    // ------------------------------------------------------------

    // Example: Rewrite origin, path, or query
    // Replace origin based on some criteria such as path or query
    const newOriginRequest = new Request(`https://origin.example.com${url.pathname}${url.search}`);
    const newOriginResponse = await fetch(newOriginRequest);
    // Return the new origin response
    return newOriginResponse;

    ...

    // Example: Rewrite request headers before reaching the origin
    // Add or modify headers before the request reaches the origin, like adding an authorization token based on exchange with an external service.
    const originRequest = new Request(req, {
      headers: new Headers({ ...Object.fromEntries(req.headers), "Authorization": "Bearer <token>" }),
    });
    const originResponse = await fetch(originRequest);
    return originResponse;

    ...

    // ------------------------------------------------------------
    // --- Response filtering: modify before client ---
    // ------------------------------------------------------------

    // Example: Change response HTML (fetch from origin, transform the body)
    // Fetch the response from the origin, transform the body, and return the transformed response.
    const originRequest = new Request(`https://origin.example.com${url.pathname}`);
    const originResponse = await fetch(originRequest);
    const transformedHtml = transformHtml(await originResponse.text());
    return new Response(transformedHtml, { status: 200, headers: originResponse.headers });

    ...

    // Example: Redirect at the edge
    // Redirect the client to a new path, like a legacy URL to a new URL.
    return Response.redirect("https://www.example.com/new-path", 301);

    ...

    // Example: Personalize by request context (geo, device, or audience)
    // Fetch the response from the origin, personalize the body, and return the personalized response.
    const originRequest = new Request(`https://origin.example.com${url.pathname}`);
    const originResponse = await fetch(originRequest);
    const personalizedHtml = personalizeHtml(await originResponse.text());
    return new Response(personalizedHtml, { status: 200, headers: originResponse.headers });

    return new Response("Not implemented", { status: 501 });
  } catch (err) {
    console.log(err);
    return new Response("Error", { status: 500 });
  }
}

Pontos principais:

Conceito
Detalhe
Filtro CDN
when + allOf em cdn.yaml roteia somente o tráfego correspondente à sua Função Edge do AEM
Solicitar filtragem
Criar um novo Request com uma origem, um caminho, uma consulta ou cabeçalhos diferentes antes de fetch() para a origem
Filtragem de resposta
Retornar um novo Response com HTML transformado, um redirecionamento ou conteúdo personalizado
Loopback de CDN
Defina um cabeçalho sentinela em chamadas internas fetch() para que a CDN roteie o tráfego de loopback para a origem

Diretrizes de design

  • Mantenha os filtros o mais estreitos possível.
  • Restringir as funções de navegação a GET e HEAD.
  • Evite loops infinitos no loopback CDN definindo um cabeçalho sentinela nas chamadas fetch() internas.
  • Implante o cdn.yaml atualizado através do seu pipeline de configuração do Cloud Manager.

Impedir loops infinitos no loopback CDN

Um loop infinito pode ocorrer quando uma Função Edge do AEM busca conteúdo da origem por meio da CDN. Essa busca entra novamente na CDN, corresponde à mesma regra de seletor de origem e é roteada de volta para a função.

Para evitar isso, você pode excluir solicitações de loopback de sua regra de seletor de origem definindo um cabeçalho sentinela (por exemplo, x-edgefunction-request). A solicitação inicial do visitante não tem cabeçalho e atinge a Função Edge do AEM. A solicitação de loopback carrega o cabeçalho, falha a condição e é roteada para a origem.

Os trechos de código e configuração a seguir demonstram como evitar loops infinitos no loopback de CDN.

// src/index.js
addEventListener("fetch", (event) => event.respondWith(handleRequest(event)));
...

// In the handler: set the sentinel on the loopback fetch
const loopbackRequest = new Request(`https://www.example.com${url.pathname}`, {
  headers: { "x-edgefunction-request": "true" },
});
await fetch(loopbackRequest);

Consulte exemplos de funções do AEM Edge para saber como definir o cabeçalho sentinela no manipulador de funções do AEM Edge.

# config/cdn.yaml (origin selector excerpt)
kind: "CDN"
version: "1"
data:
  originSelectors:
    rules:
      - name: route-to-edge-function
        when:
          allOf:
            ...
            - { reqHeader: x-edgefunction-request, exists: false } # skip loopback requests to prevent infinite loops
            ...

Consulte exemplos de funções do AEM Edge para saber como excluir solicitações que já têm o cabeçalho sentinela na configuração do CDN.

Exemplos completos

O repositório Exemplos de funções do AEM Edge inclui funções interceptoras com config/cdn.yaml regras completas:

Exemplo
Repositório
O que demonstra
Transformador do AEM as a Cloud Service HTML
publish-delivery-transformer
Publicar filtro de página para sites do AEM as a Cloud Service que injetam um trecho do JavaScript na resposta do HTML e impedem o loopback do CDN
Transformador do Edge Delivery HTML
edge-delivery-transformer
Publicar filtro de página para sites do Edge Delivery Services que injetam o cabeçalho e o rodapé do site na resposta do HTML
Redirecionar pesquisa de mapa
publicar-entrega-redirecionar-mapas
Filtro de página GET/HEAD que redireciona para uma URL herdada e impede loopback de CDN

Recursos adicionais

recommendation-more-help
experience-manager-learn-help-cloud-service