【问题标题】:Cloudfront URL rewriting/remapping so content has two URLs?Cloudfront URL 重写/重新映射,所以内容有两个 URL?
【发布时间】:2018-08-12 13:25:34
【问题描述】:

我正在管理一个具有这种模式的 URL 的文档网站:

/product-foo/1.2.3/user-guide/system-requirements.html

我希望页面有 两个 URL:

/product-foo/1.2.3/user-guide/system-requirements.html  
/product-foo/latest/user-guide/system-requirements.html

可以使用 Apache Web 服务器完成,如
http://httpd.apache.org/docs/2.4/rewrite/remapping.html

中所述

“假设我们最近将页面 foo.html 重命名为 bar.html,现在想要提供旧 URL 以实现向后兼容性。但是,我们希望旧 URL 的用户甚至不知道页面已重命名 - 那是,我们不希望在他们的浏览器中更改地址。
解决方案:我们通过以下规则在内部将旧 URL 重写为新 URL:
RewriteEngine on
RewriteRule "^/foo\.html$" "/bar.html" [PT]"

这个想法是,对于每个新产品版本,我都会更新重定向,以将“最新”模式指向最新发布版本的文档。这样人们就可以根据需要链接到最新的文档,也可以根据需要链接到特定版本的版本。

这可以通过 Cloudfront 配置 来完成吗?可以在没有 Cloudfront 的情况下单独使用 s3 完成吗?可以使用 AWS Lambda 或 Lambda@Edge 完成吗? (该解决方案会受到 Lambda@Edge 带宽限制吗?)您能否提供一个具体的示例解决方案?

【问题讨论】:

  • “解决方案是否受 Lambda@Edge 带宽限制?” Lambda@Edge 没有“带宽限制”。您是指生成的响应大小限制吗?涉及多少产品?这是相关的,因为可以实现您提出的方案,但当然需要一个映射表,以便逻辑知道每个产品的“最新”版本是什么......并且可以说,“最新”链接应该重定向到当前页面而不是备用 URL。这将是一种不同的解决方案,而不是本质上将一条路径别名为另一条路径。请澄清。
  • 谢谢你,迈克尔。是的,生成的响应大小限制。我们有 11 种产品,但期待更多。即使有预期的增加,查找表中的十几个或几十个项目似乎也是可行的。我们不想要一个简单的重定向,因为我们希望大多数人链接到最新的文档,并让他们的链接继续指向最新的文档,除非他们明确引用特定版本。一个简单的重定向会更改浏览器中的 URL,因此大多数访问者永远不会知道“最新”的 URL 格式。

标签: amazon-s3 aws-lambda amazon-cloudfront


【解决方案1】:

您可以通过多种方式做到这一点。

您可以使用新名称指向 s3 存储桶中的对象。

使用 Cloudfront 中的模式,如果没有与您的模式匹配的内容,您可以使用 API Gateway 将其发送到 lambda,您可以在其中配置通过重定向将新文件转到何处。您可以将错误路径作为 lambda 的路径参数接收。您可以在 s3 位置或发电机或任何所需的存储上维护配置。

希望对你有帮助。

【讨论】:

  • 将 lambda 附加到错误处理程序是一个意想不到的解决方案。我不愿意管理错误处理代码中的预期行为。我想要一个适当的 HTTP 响应代码:200 可能是 302。但我不反对尝试这个。您能否提供明确的信息、示例代码或指向描述捕获失败匹配桶项请求的文档的指针?我应该明确一点:我们的内容是从 S3 静态提供的,因此配置需要是 S3 交付配置的一部分,而不是单独的 EC2 服务器或类似的。
【解决方案2】:

这可以使用 Lambda@Edge 触发器来完成。 Lambda@Edge 生成的响应大小限制不适用,除非 Lambda 函数本身实际上是生成响应,方法是使用它在某处创建或获得的内容填充响应对象的 body 属性否则,从而生成函数内的响应。

使用源请求触发器:

  • 触发器仅在检查缓存后触发,并且仅在没有缓存命中时触发(缓存命中时,不联系源,因此不需要调用触发器)
  • 触发器在请求发送到源之前触发
  • 您可以修改将在请求中发送到源的路径
  • 响应缓存在浏览器最初请求的路径下,而不是修改后的路径下
  • 浏览器没有被重定向,所以地址栏没有改变。¹

基本上,我们在 Lambda 函数中需要做的就是提取请求对象,修改 URI² 并告诉 CloudFront 继续处理修改后的请求。我们只是在运行中重写部分请求,并将控制权返回给 CloudFront。

下面的示例几乎肯定不是处理一系列可能的字符串操作的最佳或最简洁的方法,但足以说明您的代码需要完成什么的一般概念,无论您使用哪种映射和匹配机制想用。

您可以静态地重新映射这些值,或者您可以使用任意数量的数据库策略来查找原始路径并找到要使用的正确当前目的地。

'use strict';

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;

    request.uri = request.uri
        .replace(/^\/product-foo\/latest\//,'/product-foo/1.0.0/')
        .replace(/^\/product-bar\/latest\//,'/product-bar/3.2.1/')
        .replace(/^\/product-three\/latest\//,'/product-three/5.5.5/');

    return callback(null, request);
};

event.Records 始终是一个仅包含一个成员的数组,event.Records[0].cf 包含此特定调用的所有相关信息。 event.Records[0].cf.request 是原始请求。修改此对象并将其作为回调的第二个参数提供,指示 CloudFront 使用修改后的请求继续正常处理。

回调的第一个参数总是null,表示没有发生异常。如果抛出异常,或者第一个参数不是 null,则 CloudFront 会向查看器返回一般错误...它不会显示异常,因为它可能包含堆栈跟踪或其他应该包含的敏感信息不被暴露。可以在 Lambda 日志中访问该错误。


¹当然,除非源服务器实际响应重定向。

²Lambda@Edge 所称的“URI”实际上只是路径。完整的 URI 在技术上是路径 + '?' + 查询字符串,但 Lambda@Edge 将这两件事分开。

【讨论】:

  • 非常感谢您!再次感谢提供源代码。我将在接下来的几天内对此进行调查。我看到请求 URL 正在更改,因此我会观察以确保浏览器中的 URL 不会更改。然而,乍一看,这看起来正是我所追求的。
  • request.uri 是 CloudFront 发送到源服务器的路径,此处。它绝对不应该改变浏览器地址栏中的内容......除非出于任何原因您的源服务器生成后续重定向。
猜你喜欢
  • 2012-08-11
  • 2020-12-13
  • 1970-01-01
  • 2016-03-07
  • 1970-01-01
  • 2016-08-30
  • 1970-01-01
  • 2015-05-23
  • 2011-11-11
相关资源
最近更新 更多