我正在帮助为 NGINX HLS 视频源实施 CloudFront CDN。如果您不熟悉,浏览器中的 HLS 仅使用 XHR 或 fetch 通过 HTTP 不断请求 .m3u8 和 .ts 文件并将它们显示在视频元素中。我已经使用间隔内的简单 AJAX 调用复制了我所描述的问题,因此该问题并非特定于 HLS。我希望能够在 CDN 和直接到源之间切换流量,同时对用户的影响最小。我已经构建了它,并且可以通过更改 Route 53 中的 DNS 在 CloudFront 和直接到源之间切换。DNS 记录的 TTL 为 1 分钟
但是,当我这样做时,有时浏览器使用的 IP 地址不会改变 - 即使在 DNS TTL 之后很长时间也是如此。操作系统和浏览器级 DNS 缓存显示预期的 IP 地址,但浏览器(如开发人员工具 -> 网络所示)显示它仍在使用“旧”IP 地址。在 DNS TTL 之后,它可以继续这样做几个小时。即使刷新页面也不会强制它为域获取新的 IP。到目前为止,我只发现 chrome://net-internals/#sockets -> Flush Socket Pools 或完全关闭所有浏览器实例会强制浏览器为域获取新的 IP 地址。
因此,我相当确定问题在于 Chrome(也测试了 FireFox,可能是所有浏览器)保持连接,并且在连接关闭之前不会再次查找 DNS,无论 DNS TTL 如何,尤其是对于 HLS 视频或连续 ajax 轮询,其中每隔几秒钟就会使用一次连接。我可以通过在源上设置 Connection:close 或 Keep-Alive:timeout=5s 标头来对此进行某种控制。但是,我无法在 CloudFront 上控制这些,即使使用自定义函数也是如此。此外,如果我在源和/或 CloudFront 上启用 HTTP2,则不允许或使用这些标头,但我仍然看到类似的行为。
我还可以从源返回 HTTP 421 错误重定向请求,并强制客户端刷新源。但是,这在 CloudFront 中不起作用 - 使用 CloudFront 函数修改响应代码会导致错误,而从源返回到 Cloudfront 的 421 会导致错误并且不会触发客户端刷新。
考虑到所有这些,我如何确保 DNS 更改在 DNS 条目的 TTL 内的浏览器中生效?我可以使用任何标头或 CloudFront 设置吗?我可以控制一些客户端,那么是否有任何 javascript、请求标头或 XHR 技巧可以强制浏览器获取并使用新的 TTL?