安全媒体上传已过期

我们有一位客户在安全媒体上传方面遇到问题。
该客户运行的是基于 Docker 的 Discourse(官方安装),并启用了 AWS S3 和安全媒体功能。

论坛中包含多个 mp3 和 m4a 音频文件。

Discourse 会自动嵌入一个类似以下的播放器:

image

问题:音频文件无法可靠播放。有时它们无法播放。

我无法 100% 稳定地复现此问题,我认为这可能与缓存有关,但看起来下载会被推迟到点击播放按钮时才开始。这听起来合乎逻辑且合理。

但这与安全媒体上传不兼容——如果您将页面保持打开状态一段时间,然后在几分钟后点击播放按钮,音频文件将(并非总是)无法播放。此时,AWS 会返回一个 403 Expired 错误。看起来请求在文件被请求时并未签名,而是在更早的时候签名的。错误消息明确指出请求已在过去过期。

我怀疑这与延迟有关,但我并不 100% 确定。事实是,这个问题仅出现在音频文件上(即嵌入的图片不会出现此问题,因为它们总是立即下载)。

是的,服务器时间是正确的。

我可以在运行最新测试版的全新安装上复现此问题。只需在某个主题中放入两个音频文件,然后进行一些操作即可。

2 个赞

这可能是因为浏览器处理音频和视频标签的方式以及 preload 的默认值。这些文件是否特别长?据我所知,浏览器会按需使用字节范围下载。

4 个赞

不,它们并不长,文件只有几(< 5)兆字节,而且并没有进行范围下载。

你说的“preload 的默认值”是什么意思?

如果你有 <audio><video> 标签,为其设置 preload=auto 属性,会提示浏览器在页面加载时下载整个文件,这样你就不会遇到签名 S3 URL 过期的问题了。

不过,正如这类情况常发生的那样,网站开始滥用该属性,因此浏览器现在不再总是无条件遵循它,但它仍是一个浏览器会考虑参考的提示。

6 个赞

没有显式的 <audio> 标签,它是由 Discourse 在插入音频文件时自动生成的,且没有 preload 属性。

我不理解的部分是:如果 /secure-media-uploads 路由负责生成签名 URL,那么页面加载与触发该路由之间的时间间隔为何会有影响?毕竟,它是生成签名路由后立即重定向到该地址的。但不知为何,这似乎确实有影响。感觉像是有什么东西被缓存了,还是别的什么原因?

在帖子 Markdown 生成的 HTML 中确实存在该标签,我讨论的正是这一点。我认为在启用该设置时添加该属性是有意义的。

我认为该功能的整个要点恰恰在于此。让上传文件的 URL 无法在其他地方被分享,而实现这一点的唯一方式就是使用会过期的 URL。

5 个赞

是的,我明白这一点。而且过期计时器是在调用 /secure-media-uploads 路由时开始计时的,而不是在页面加载时。

不过,似乎页面在很久以前加载,之后才触发该路由,这确实会产生影响。然后就会出错,不知何故。我只是不明白为什么会这样。

此问题已在此处修复:FIX: Disable preloading audio + video when secure media enabled (#8922) · discourse/discourse@7ff58f1 · GitHub @RGJ。该问题出现的原因是,浏览器会向音频和视频文件发送初始请求以获取文件的元数据(例如时长)。然而,由于使用了安全的预签名 URL,该初始请求会触发 15 秒的过期倒计时,因此当用户在此时间段后尝试播放音频或视频时,我们会收到来自 AWS 的 403 错误。

现在,在启用安全媒体时,我们将禁用视频和音频的预加载。包含音频和视频的现有帖子需要重新构建其 HTML 才能看到此更改。

13 个赞