无法下载 js 附件

我遇到了与这个问题完全相同的错误:即我可以在设置中允许后上传 js 文件,但当我尝试下载时,浏览器中的 URL 会变为 js 文件 URL,并显示“您想要的更改被拒绝”。

环境:
Discourse Docker 运行在 Nginx 之后(Nginx 使用 SSL)

Discourse 容器日志:

    Started GET "p5ePkm5OoKveknnMjyArlS4PPwS.js" for 192.168.32.1 at 2021-02-22 05:48:52 +0000
    Processing by UploadsController#show_short as JS
      Parameters: {"base62"=>"p5ePkm5OoKveknnMjyArlS4PPwS", "extension"=>"js"}
    Sent file afcdf626f9db8d54a1fb5e8ebcab0ea214d9226a.js (2.2ms)
    Security warning: an embedded <script> tag on another site requested protected JavaScript. If you know what you're doing, go ahead and disable forgery protection on this action to permit cross-origin JavaScript embedding.
    Completed 422 Unprocessable Entity in 59ms (ActiveRecord: 0.0ms | Allocations: 17414)
    ActionController::InvalidCrossOriginRequest (Security warning: an embedded <script> tag on another site requested protected JavaScript. If you know what you're doing, go ahead and disable forgery protection on this action to permit cross-origin JavaScript embedding.)
    /opt/bitnami/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.3.1/lib/action_controller/metal/request_forgery_protection.rb:266:in `verify_same_origin_request'

Nginx 日志:

    10.164.0.103 - - [22/Feb/2021:05:51:11 +0000] "GET /uploads/short-url/p5ePkm5OoKveknnMjyArlS4PPwS.js HTTP/2.0" 422 781 "getting-started-with-sftp-module/292" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36"

任何帮助或建议都将不胜感激!

2 个赞

您是否允许用户将 *.js 文件附加到帖子中?您的用户是否有合法的需求来附加 JavaScript 文件?在继续之前,我们想再次确认这一点。

1 个赞

感谢您的快速回复!
是的,这是一个关于编程问答的讨论,因此附加 *.js 代码文件是合理的使用场景。

2 个赞

大家好!我也遇到了同样的问题。我们已经允许上传 .js 文件,但没有人能下载它。目前还没找到任何设置来解决这个问题。有人能帮忙吗?

1 个赞

能否描述一下使用场景?为什么这是必要的?

你好,Jeff,

不过,我们现在是将代码复制并粘贴到帖子的文本区域中。
使用场景:我们有一个包含 Kickstarter 代码或解决重复性问题的方案的 .js 文件,希望将其作为附件分享,以便用户可以下载并在自己的项目中直接使用。

然而,如果我们把文件扩展名从 .js 改为 .txt,系统又会显示“您想要的更改被拒绝。”(这可能是由于后端进行了某种存储优化:如果文件内容与之前上传的文件相同,新附件会直接指向之前上传的文件。)
因此,我稍微修改了 .txt 文件(原为 .js 扩展名)的内容,然后重新上传,最终成功将文件作为附件下载。

@codinghorror 允许下载 .js 文件是否存在安全风险?

1 个赞

是的;我们需要进行一些浏览器研究,以确保文件始终下载到磁盘而不会被执行。

1 个赞

我们在 fluiggers.com.br 上有一个开发者论坛,欢迎查看……我们经常会分享 .js 文件。

1 个赞

当然,允许加载 JS 文件存在诸多安全隐患,因此我们必须对此格外谨慎。

Content-Disposition 响应头会阻止下载的 JS 文件被执行,而我们已经正确设置了该头:

attachment; filename="test.js"; filename*=UTF-8''test.js

该设置在 S3 上传场景中有效,在本地上传场景中本应同样有效,但似乎 Rails 引入了一项新的(或近期更新的)安全措施:

ActionController::InvalidCrossOriginRequest(安全警告:来自其他站点的嵌入式 <script> 标签请求了受保护的 JavaScript。如果您了解相关操作,请继续并在此操作上禁用 CSRF 保护,以允许跨源 JavaScript 嵌入。)

这个问题应该是可以修复的……

3 个赞

我遇到了同样的问题,我们有一个编码问答论坛,需要能够共享大型 js 文件以下载。

我的社区也遇到了同样的问题。人们想分享 JS 文件,但在尝试下载时会收到此错误:

来自 rails 生产日志的摘录:

Started GET "/uploads/short-url/qDlrltMxEIJ2aYYdt8lZ200E3wA.js" for 94.31.111.247 at 2025-07-09 05:53:30 +0000
Processing by UploadsController#show_short as JS
  Parameters: {"base62"=>"qDlrltMxEIJ2aYYdt8lZ200E3wA", "extension"=>"js"}
Sent file /var/www/discourse/public/uploads/default/original/1X/baab1fc131be960b601467333f5a690b257daeb0.js (0.3ms)
Security warning: an embedded <script> tag on another site requested protected JavaScript. If you know what you're doing, go ahead and disable forgery protection on this action to permit cross-origin JavaScript embedding.
Completed 422 Unprocessable Entity in 17ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms)

js 文件在允许的上传扩展名列表中:

同样的问题也出现在我们这里。我们有一些 js 文件在我们自己的软件中运行,这些文件绝不会在浏览器中执行任何操作。

我们通过将所有上传内容移至 S3 存储桶并将 s3_use_cdn_url_for_all_uploads 设置为 true,成功解决了 Discourse 的下载问题。这实际上绕过了短 URL 控制器,而该控制器似乎是导致 js 文件无法使用的根本原因。

具体步骤(由我的 AI 指导我完成):

  1. 设置 S3 兼容存储(例如 Cloudflare R2)

Discourse 无法安全地从本地磁盘提供 .js 文件。请将其移至存储桶。

  • 存储桶:创建一个私有存储桶(例如 my-discourse-bucket)。

  • API 密钥:生成访问密钥和密钥。

2. 配置自定义 CDN 域名

在 Cloudflare(或您的提供商)中,将自定义域名连接到您的存储桶(例如 cdn.example.com)。这确保文件通过直接 URL 作为静态资源提供,从而绕过 Discourse 的“安全卫士”。

3. 更新 Discourse 设置

管理 → 设置 中配置您的 S3 详细信息。关键的是,启用以下选项以确保 Discourse 不会尝试使用可能破坏链接的临时标头来“签名”URL:

  • s3_use_cdn_url_for_all_uploads勾选此框(这是最重要的步骤)。

  • s3_cdn_url:设置为 https://cdn.example.com

  • s3_region:使用 us-east-1(适用于 R2 兼容性)。

4. 迁移现有上传(可选)

注意:由于未知原因,此方法对我们无效。

要修复现有帖子中的旧链接,请进入您的容器并运行:

Bash

# 在 /var/discourse 内
./launcher enter app
rake uploads:migrate_to_s3
rake posts:rebake

希望这对大家有所帮助。