1

我有一些旧的 URL 过去使用大写字母来表示人名等,但现在我已经将我的网站更新为每个页面的 URL 中的小写字符。所以,如果人们碰巧点击了旧链接,或者不小心输入了大写字母,我想重定向他们。

我还检查删除尾部斜杠。这是我目前在前端使用的代码。我希望切换到使用 Lambda@Edge(我的网站在 S3 上并通过 CloudFront 分发)进行检查和重定向。

这是我在前端使用的 JS 函数:

var newUrl = window.location.href.toLowerCase().replace(/\/$/, '')

loadIfChanged(newUrl)

function loadIfChanged (newUrl) {
  if (newUrl != location.href) {
    fetch(newUrl, {method: 'HEAD'}).then(function (response) {
      if (response.status === 200) return window.location = newUrl
    }).catch(function (error) {
      return console.log(error)
    })
  }
}

我如何在 Lambda@Edge 函数中编写它?

也许是这样的:

exports.handler = async function (event, context) {
  // Lowercase the URL and trim off a trailing slash if there is one
  var path = event.Records[0].cf.request.uri.toLowerCase().replace(/\/$/, '')

  // How to do a fetch here? var ok = fetch()

  if (ok) {
    const response = {
      status: '301',
      statusDescription: 'Moved Permanently',
      headers: {
        location: [{
          key: 'Location',
          value: `https://example.com/${path}`,
        }],
      },
    }
    return response
  } else {
    return event.Records[0].cf.request
  }
}

Lambda@Edge 函数甚至可以进行 I/O 吗?

而且,重要的是,这个 Lambda@Edge 函数只能在 404 上运行吗?

4

1 回答 1

2

你写的应该可以工作,但我认为更好的实现是简单地更改OriginRequest Lambda 函数中的 URI。代码很简单:

import json

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request'];
    request['uri'] = "anything";

    return request;

这里要注意的一个有趣的细节是,CF 将根据原始 URI 缓存修改后的 URI 的结果。因此,如果再次请求原始 URI,CloudFront 将直接从缓存中返回响应。

为什么是原始请求?

  1. 因为它仅在缓存未命中时触发
  2. 它有助于获得上述缓存的好处

为什么这种方式比你提出的更好?
如果您决定采用上述方法,以下是请求流程:
对于非缓存内容:

User -> CF -> Lambda -> S3 -> Final response to the user   

对于缓存的内容:

User -> CF -> Final response to the user   

而如果您使用 Lambda 生成 301,则流程将是:
对于非缓存内容:

User -> CF -> Lambda -> User -> CF -> Lambda -> S3 -> Final response to the user  

对于缓存的内容:

User -> CF(cf returns 301) -> User -> CF -> Final response to the user  

因此,您在这种方法中获得了两个优势:

  1. 为您的用户减少延迟。
  2. 更少的 lambda 调用,这意味着你的账单更少。

对于您的第二个问题,我认为目前没有任何方法可以仅为 404 调用 Lambda@Edge。

希望这可以帮助!

于 2019-10-11T19:44:02.123 回答