JavaScript嵌入无法显示嵌入,控制台日志显示:无法在DOMWindow上执行postMessage…

你好,我在尝试将 JavaScript 嵌入集成到我们的网站时遇到了完全相同的错误。

我已经查看了相关主题并进行了谷歌搜索,但仍不确定该如何解决此问题。谢谢!

[编辑] 由于我不想让此错误消息一直显示,因此我仅在此一篇旧帖子中启用了它。

嵌入设置:

尝试过的设置:

host: royaleapi.com
path allowed: /blog/.*

host: royaleapi.com
path allowed: 

我还为以下域名启用了 CORS 来源:

  • https://royaleapi.com
  • https://cdn.royaleapi.com

此外,我还在 app.yml 的 ENV 中添加了 DISCOURSE_ENABLE_CORS: true,所以我现在有点卡住了……

你确定 ?discuss=1 查询参数不是导致问题的原因吗?

你的博客分类是否设置了任何安全权限,还是已设置为允许“所有人”组进行“创建/回复/查看”?

你的网站使用的是哪个版本的 Discourse?

另外,在 Failed to execute postMessage on DOMWindow 文本之后,你看到的具体错误信息是什么?我预计它应该是类似 The target origin provided (<target_url>) does not match the recipient window's origin (<origin_url>) 的内容。

我确定这与 ?discuss=1 参数无关。没有它我也遇到过同样的问题——只是因为这是一个在线站点,我不想向我们的用户显示巨大的错误块。但既然你问了,我已经编辑了站点,改为仅在我们的一篇非常旧的帖子中启用 JavaScript 嵌入,那里应该不会有访客。所以没有查询字符串。(我已更新我的首条帖子以反映这一点)

https://royaleapi.com/blog/season3

https://royaleapi.com/blog/season3

Discourse 版本

2.6.0.beta5

操作系统版本

Ubuntu 20.04.1 LTS

完整错误信息

VM469 embed-application-9cef8308c816fc1d83137e63d6c556c6cc2b68fe2b6e5ce16cca6766ba2c0ae4.js:1 在 ‘DOMWindow’ 上执行 ‘postMessage’ 失败:提供的目标源(‘https://discuss.royaleapi.com’)与接收窗口的源(‘https://royaleapi.com’)不匹配。

博客分类

这是一个公开分类——对所有人开放。我实际上已经将其设置为没有帖子。我刚刚创建了一篇新帖子,以查看该分类中是否必须包含单个项目。

截图:桌面端

截图:移动端

不确定这是否相关,但我在日志中看到了一些错误,不过我不确定具体是什么:

[Fri 06 Nov 2020 04:47:14 PM UTC] 域名未更改。
[Fri 06 Nov 2020 04:47:14 PM UTC] 跳过,下次续期时间为:Mon 04 Jan 2021 08:07:59 AM UTC
[Fri 06 Nov 2020 04:47:14 PM UTC] 添加 '--force' 以强制续期。
[Fri 06 Nov 2020 04:47:14 PM UTC] 正在将密钥安装到:/shared/ssl/discuss.royaleapi.com_ecc.key
[Fri 06 Nov 2020 04:47:14 PM UTC] 正在将完整证书链安装到:/shared/ssl/discuss.royaleapi.com_ecc.cer
[Fri 06 Nov 2020 04:47:14 PM UTC] 运行重载命令:sv reload nginx
警告:nginx:无法打开 supervise/ok:文件不存在
[Fri 06 Nov 2020 04:47:14 PM UTC] 重载错误:
已启动 runsvdir,PID 为 663
ok: run: redis: (pid 677) 0s
chgrp:无效的组:'syslog'
ok: run: postgres: (pid 675) 0s
rsyslogd: imklog:无法打开内核日志 (/proc/kmsg):操作不允许。
rsyslogd: imklog 模块激活失败 [v8.1901.0 请查看 https://www.rsyslog.com/e/2145 ]
supervisor pid: 671 unicorn pid: 702

另外,请告诉我其中是否有任何内容需要脱敏。既然我已经发布了该 URL,我认为这应该无害,因为这些文件路径看起来是该环境的标准配置。

@simon 这是否有可能由您协助解决?这是预期行为,还是将在未来的版本中修复?

我们添加这个论坛主要是为了支持在我们网站页面上进行评论。如果此功能无法使用,我们需要考虑其他解决方案。

谢谢!

这张截图中有一个我之前没注意到的问题:

路径白名单被设置为 /blog/*,而不是 /blog/.*(注意多了一个点号)。

尝试编辑主机条目,将路径白名单更改为 /blog/.*

如果这不能解决问题,请尝试 /.*。也可以尝试将该设置留空。

是的,我的截图确实显示了该问题,但我后来意识到它很可能使用了正则表达式,因此已经将其改为 /blog/.*。不过,问题仍然存在。

@simon 我已经尝试了以下三种方式:

/blog/.*
/.*

(最后一个是空的),但都不起作用。

我在控制台中看到的错误看起来更像是 CORS 问题:

_embed-application-9cef8308c816fc1d83137e63d6c556c6cc2b68fe2b6e5ce16cca6766ba2c0ae4.js:7 
在 'DOMWindow' 上执行 'postMessage' 失败:
提供的目标源 ('https://discuss.royaleapi.com') 
与接收窗口的源 ('https://royaleapi.com') 不匹配。

但我不确定该如何修复。为了测试,我已经在应用配置中添加了以下内容:

  DISCOURSE_ENABLE_CORS: true
  DISCOURSE_CORS_ORIGIN: '*'

基本上将其设置为完全开放,但这仍然不起作用。

在 Discourse 嵌入设置页面中,您是否已设置“创建话题的用户名”选项?如果未设置,您将遇到 Failed to execute 'postMessage' on 'DOMWindow' 错误。

@simon 是的,创建主题的用户名已设置为 system。我也尝试将其设置为我自己的用户名,但出现了相同的错误。

值得注意的是,今天我发现了以下情况:

curl -IXGET https://discuss.royaleapi.com
access-control-allow-origin: *
access-control-allow-headers: Content-Type, Cache-Control, X-Requested-With, X-CSRF-Token, Discourse-Present, User-Api-Key, User-Api-Client-Id, Authorization
access-control-allow-credentials: true
[已截断]

然而:

curl -IXGET https://discuss.royaleapi.com/javascripts/embed.js
HTTP/2 200
server: nginx
date: Tue, 08 Dec 2020 23:52:26 GMT
content-type: application/javascript
content-length: 2404
last-modified: Tue, 01 Dec 2020 01:49:39 GMT
vary: Accept-Encoding
expires: Wed, 09 Dec 2020 23:52:26 GMT
cache-control: max-age=86400
cache-control: public,immutable
accept-ranges: bytes

这是否就是原因?看起来脚本本身并没有 access-control-allow-origin 头,即使域名有。我是否应该尝试使用自己的 nginx 配置,而不是使用 Docker 镜像中内置的配置?

@simon 我已解决此问题。

为了解决另一个问题 https://meta.discourse.org/t/unable-to-generate-preview-for-urls/175758/4,我在网站上启用了 HEAD 请求。现在所有讨论都已显示,我的博客文章也自动生成了相应的主题。

这太棒了——我简直不敢相信,我竟然钻进了判断这是否与 CORS 相关的牛角尖,而实际上问题出在 HEAD 请求上。或许需要在文档中明确说明这一点。

请将此问题标记为已关闭。

非常感谢您跟进此事!

或许应该将此内容添加到 Embed Discourse comments on another website via Javascript 的“故障排除”部分。我不确定 HEAD 请求被禁用的情况有多普遍,但对于那些禁用了 HEAD 请求的网站来说,排查这个问题相当困难。

好吧,如果你特意去拦截那些对 GET 请求有响应的 URL 的 HEAD 请求,从而违反了 RFC,那么出现一些故障不是也在情理之中吗?

说实话,我没想到有服务依赖它的存在。如果我知道它是必需的,我就不会“禁用”这个方法了。

另外,澄清一下:我并不是特意要去禁用这个方法。我只是没有编写支持 HEAD 方法的路由。所以我现在所做的,就是添加一个函数,来响应所有发往有效端点的 HEAD 请求。

实际上,@Falco 指出只需运行

curl https://example.com/path/to -I

即可显示该方法是否已实现。这看起来是一个很好的检查方式。

无论如何,非常感谢你们两人的帮助!

哦,抱歉。我想是像 Rails 这样的框架把我宠坏了,以至于我以为这应该是网站开箱即用的默认行为 :sweat_smile:

好的,请更新故障排除部分,加入以下内容。我遇到了 CORS/帧安全方面的问题,希望按照 @seeminglee 的步骤操作能有所帮助。如何启用 HEAD 请求?

@willywongi 你可能对我的问题有些误解,让我来解释一下具体情况。

  1. 我按照步骤操作了,但无法将评论嵌入到网站中。
  2. 后来发现,我的 Discourse 应用(安装在另一个域名上)无法“验证”我的博客文章是否存在,因为我的主站没有在这些 URL 上实现 HEAD 方法。
  3. 在为这些路径实现 HEAD 请求处理器后,嵌入功能便正常工作了。

要检查你是否遇到和我一样的问题,可以对包含博客文章的 URL(或你希望评论嵌入出现的位置)运行 curl 命令。

例如,如果你的 URL 是 https://example.com/blog/awesome-post,请在终端中运行:

curl https://example.com/blog/awesome-post -I

这将向该 URL 发送一个 HEAD 请求并返回结果。如果状态码不是 200(即响应第一行的数字),例如:

HTTP/2 200

则说明服务器未实现 HEAD 方法(或者在响应时存在问题)。

如果响应状态码确实是 200,那么嵌入问题与 HEAD 请求无关。

哈哈,现在清楚了!谢谢。
我检查了 HEAD 方法,我的网站能正确(200)响应。

我仍在努力嵌入 Discourse 主题,但如果其他任何地方失败,我会另开一个新主题。

遇到这个问题,结果发现是因为我更改了“创建主题的用户名”的调用方式,却忘记在嵌入页面中更新它。我想它试图创建主题却找不到用户名。在嵌入设置页面更新后,错误就消失了。