非图片上传未使用 S3 CDN URL

Maybe related to S3 CDN URL ignored when uploading into posts.

At first I thought I had missed some configuration, but it’s reproducible here on meta:
https://meta.discourse.org/uploads/short-url/dw1U4hctATusBlHsUmWQXeme66j.csv (uploaded here) is a 302 redirect to
//assets-meta-cdck-prod-meta.s3.dualstack.us-west-1.amazonaws.com/original/3X/5/e/5ebb2cfb8cc907e8e8f7c6559a72d2f4a8ba2f8f.csv

Shouldn’t it redirect to https://d11a6trkgmumsb.cloudfront.net/original/3X/5/e/5ebb2cfb8cc907e8e8f7c6559a72d2f4a8ba2f8f.csv instead?

5 个赞

Hmmm there may possibly be an issue here @martin can you investigate? We should probably redirect to the CDN if possible.

5 个赞

This is a little bit tricky, I had a look at this just now. Basically we are always downloading from S3 with a presigned URL if we are doing a “force download”, which is what happens when we are clicking on the attachment link or clicking on the Download button on an image. This is so the appropriate content-disposition headers can be added:

attachment; filename="#{upload.original_filename}"; filename*=UTF-8''#{upload.original_filename}

I do not think it is possible to make the CDN URL behave in this way? The CDN URL for images is only used when displaying them inline, not when downloading them. Also in the case of secure images and attachments which have a private ACL the presigned URL must always be used.

2 个赞

@martin 关于附件链接,我无法看到它们如何设置为始终“强制下载”。目前,在上传非图像文件时,生成的渲染 URL 是一个没有 ?dl=1 参数的短 URL,它被解析为相应上传的 url 属性的值(它不是预签名 URL,并且在我们的情况下也会失败,因为 URL 不是 S3 cdn_url,而是可能仅适用于某些 S3 提供商的构造 URL)。

是否有办法始终强制下载附件,或者当前行为实际上是一个错误?

1 个赞

你能详细说明一下吗?你使用的是 Amazon S3 还是其他提供商?如果是,是哪一个?

1 个赞

是的,我似乎在使用一个_不支持_的 S3 提供商(OVH 对象存储

端点 URL 为 https://s3.de.ovh.cloud.net,配置的 s3 cdn_url 为 https://storage.de.ovh.cloud.net/v1/<some-unique-user-id>/<the-bucket-name>

当解析短 URL 时,Discourse 使用端点 URL 来构建生成的 URL(这会失败,因为它不包含正确的 OVH 用户 ID - s3 cdn_url 中的一部分)。

然而,强制短 URL 具有 dl=1 会构建一个有效的预签名 URL,这对我来说就足够了。

我在容器 YAML 中设置了这些(s3 特定的)环境变量:

DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: DE
DISCOURSE_S3_ENDPOINT: https://s3.de.cloud.ovh.net
DISCOURSE_S3_ACCESS_KEY_ID: ...
DISCOURSE_S3_SECRET_ACCESS_KEY: ...
DISCOURSE_S3_CDN_URL: https://storage.de.ovh.cloud.net/v1/<some-unique-user-id>/<the-bucket-name>
DISCOURSE_S3_UPLOAD_BUCKET: <the-bucket-name>
DISCOURSE_S3_INSTALL_CORS_RULE: false
1 个赞

也许这超出了本主题的范围,但如果当前行为是故意的,那么如何在前端覆盖短 URL 渲染?我想直接挂钩到帖子的烘焙过程,然后将查询参数附加到附件短 URL。我知道如何为 Discourse 编写 JS 插件,但大多数时候我只是很难找到正确的 Widget 来“重新打开”或覆盖函数。

好的,我找到了生成 Markdown 附件 的地方,据我所知,插件 API 无法(轻松地)覆盖它(我甚至认为不应该这样做)。

所以,我最初想在这些 URL 中添加 ?dl=1 参数的想法似乎是错误的方法。

关于不强制下载已解析的短 URL:如果我正确理解了 S3 存储桶公共 ACL 的反对意见,那么应该:

  1. 通过 CDN 提供 S3 文件(正如 @martin 指出的,对于附件来说是不可行的,因为在这种情况下我们可能无法正确设置下载文件名)
  2. 为 S3 对象创建预签名 URL

但目前的行为既没有这样做,也没有期望 S3 存储桶具有公共 ACL。对于支持的 S3 提供商(包括亚马逊)似乎也是如此,那么为什么在解析 S3 存储的短 URL 时,不将 Discourse.store.url_for 中的 force_download 选项默认设置为 true 呢?

1 个赞

我在这里遇到同样的问题,我期望的是 uploads/short-url 后面的文件能通过 S3 CDN URL 下载或重定向。

2 个赞

我们遇到了与Cloudflare R2相同的问题,因为它似乎不允许在没有预签名URL的情况下使用直接S3 URL。
而且R2不支持存储桶的ACL。

看起来 discourse 最近添加了一个“s3 use cdn url for all uploads”(对所有上传使用 CDN URL),这解决了这个问题。