Safari 中的 Rail、ajax 和 iframe

Rail, ajax and iframe in Safari

在我们的应用程序中,我们有一些与 ajax 一起使用的元素。 我们允许用户将部分应用程序嵌入到 iframe 中。

在 Chrome 和 Mozilla 中一切正常。在 Safari 中我们收到 422 错误,服务器日志如下所示:

2015-07-15T08:26:06.818885+00:00 app[web.1]: Completed 422 Unprocessable Entity in 4ms
2015-07-15T08:26:06.815411+00:00 app[web.1]: Can't verify CSRF token authenticity
2015-07-15T08:26:06.823389+00:00 app[web.1]: ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):

我们发现如果我们直接访问 iframe url 然后访问包含 iframe 的页面它工作正常,这可能表明它与 cookie 有关。

我试过了this solution,但还是有这个问题。

最后我发现 Safari 不允许在 iframe 中保留 cookie。

也就是说,如果你需要使用cookies,你需要做一些事情。

我找到的解决方案是这样的:

  1. 在 iframe 代码中检查 session[:safari_cookie_fixed] 是否存在。如果不是,请呈现一个代码,该代码将使用 postMessage 与父 window 进行通信,并让他知道我们需要重定向。
  2. 加载 iframe 时,父级 window 通过 postMessage 向 iframe 发送信号。在 cookie 不存在的情况下呈现的侦听器向父级发送信号以执行重定向,父级重定向到 iframe 域中的 /set-cookie 页面,添加其当前 url作为查询字符串参数。
  3. set_cookie 操作保存 cookie safari_cookie_fixed 并重定向回父页面(其 url 在查询字符串中可用)

当然,此解决方案需要在父页面中添加一些 js 代码,但是当您为用户提供 iframe html 代码时,您也可以包含 js。

Safari 不允许(默认情况下)在 iFrame 中设置 cookie,除非用户已经访问过该站点。想象一下这段代码:

# a.com
<iframe src="b.com/iframe">

如果您直接访问 b.com(任何页面)并且它设置了一个 cookie,那么当您访问 a.com 并且加载到 b.com 的 iFrame 时,Safari 将发送该 cookie。

但是,如果您在没有先访问 b.com 的情况下访问 a.com,则 Safari 将忽略 b.com/iframe 尝试设置的任何 cookie。

名为 "A solution for Safari" 的部分中的 solution is described here

  1. 检测是否支持cookies。
  2. 如果没有,在页面上放置一个叠加层说,"This site requires cookies. Please click here to continue."
  3. 当用户点击 link/button 时,打开一个弹出窗口,它设置一个 cookie 并自行关闭。在桌面上,您可以使弹出窗口相当小且无害。在移动设备上它更难看,因为你不能让弹出窗口小于全屏。但是,无论哪种方式,弹出窗口仅在屏幕上显示不到一秒钟。
  4. iframe 会自行重新加载,现在可以使用 cookie。