包含Edge函数的HTTP请求过滤器

IMPORTANT
AEM Edge函数当前为测试版。 功能和文档可能会更改。 如需反馈,请联系aemcs-edgecompute-feedback@adobe.com

了解如何使用AEM Edge函数实施HTTP请求筛选,以重写或重定向请求,或修改HTTP响应。

何时使用Edge函数筛选HTTP请求

AEM Edge函数可以充当反向代理,在请求和响应到达源或客户端之前对其进行高级处理。

这两种情况是:

在请求到达源之前对其进行调整

在前往来源的路上截获流量以:

  • 重写请求源、路径或查询。 将请求路由到不同的后端、路径或查询字符串,以便源接收正确的资源。
  • 重写请求标头。 在请求到达源之前,添加、删除或修改标头。 例如,添加来源需要的地理位置或访问标头,删除来源忽略的标头,或更改标头值以改变请求行为。

在响应到达客户端之前对其进行修改

在返回客户端(访客)的路上拦截流量,以:

  • 更改响应HTML。 在页面到达浏览器之前,在页眉和页脚中插入JavaScript、个性化内容、重写链接或拼合。
  • 在边缘重定向​ 从CDN提供大量旧版到新版URL重定向,尤其是当重定向规则需要编程逻辑时。
  • 按请求上下文个性化。 对于公共访客,根据地理位置、设备或受众而改变页面或页面部分。 这适用于网站域上的发布流量,不适用于创作流量。

实施HTTP请求筛选

HTTP请求筛选使用两个文件。 config/cdn.yaml文件决定要拦截哪些流量并路由到您的AEM Edge函数。 src/index.js文件执行请求或响应调整。

原始选择器和函数名称必须对齐。 如果edgeFunctions.yaml声明my-edge-function,则原始选择器在cdn.yaml中使用edgefunction-my-edge-function

配置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>

如果任何条件失败,则请求永远不会到达AEM Edge函数。 从函数所需的最少条件开始,仅添加更多条件以提高路由精度。 有关所有支持的属性和运算符,请参阅原始选择器

实施处理程序

每个AEM Edge函数都注册一个获取事件处理程序。 使用处理程序在请求到达源主机之前调整请求,在响应到达客户端之前修改响应,或同时修改两者。

以下代码片段演示了AEM Edge函数中的请求过滤和响应修改。

// 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 });
  }
}

要点:

概念
详细信息
CDN过滤器
cdn.yaml路由中的when + allOf仅路由与您的AEM Edge函数匹配的流量
请求筛选
fetch()之前生成一个新Request,其来源、路径、查询或标头不相同,以作为来源
响应筛选
返回包含转换后的HTML、重定向或个性化内容的新Response
CDN环回
在内部fetch()调用上设置Sentinel标头,以便CDN将环回流量路由到源

设计准则

  • 筛选器应尽量缩小。
  • 将导航功能限制为GETHEAD
  • 通过在内部fetch()调用上设置Sentinel标头,避免在CDN环回上出现无限循环。
  • 通过您的Cloud Manager配置管道部署更新的cdn.yaml

防止CDN环回上的无限循环

当AEM Edge函数通过CDN从源获取内容时,可能会发生无限循环。 该获取操作将重新进入CDN,匹配相同的原点选择器规则,然后路由返回函数。

要防止出现这种情况,您可以通过设置一个Sentinel(例如,x-edgefunction-request)标头,从源选择器规则中排除环回请求。 初始访客请求没有标头,达到了AEM Edge功能。 环回请求携带标头,未能满足条件,转而路由到原点。

以下代码和配置片段演示了如何防止在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);

有关如何在AEM Edge函数处理程序中设置Sentinel标头的信息,请参阅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
            ...

请参阅AEM Edge函数示例,了解如何在CDN配置中排除已包含Sentinel标头的请求。

完整示例

AEM Edge函数示例存储库包含具有完整config/cdn.yaml规则的侦听器函数:

示例
存储库
它展示的内容
AEM as a Cloud Service HTML transformer
publish-delivery-transformer
AEM as a Cloud Service​站点的发布页面过滤器,用于将JavaScript代码片段注入HTML响应并阻止CDN环回
Edge Delivery HTML transformer
edge-delivery-transformer
将站点页眉和页脚注入HTML响应的​ Edge Delivery Services ​站点的发布页面筛选器
重定向映射查找
publish-delivery-redirect-map
重定向到旧版URL并阻止CDN环回的GET/HEAD页面筛选器

其他资源

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