11

伙计们,我有一个 Web 应用程序,我在其中对同一资源的 JSON 和 HTML 表示重新使用了相同的路由,现在我们称之为 /foo/details。此页面链接自,我们称其为 /bar/details。(因此,查看 /bar/details 您会看到指向 -> /foo/details 的链接)。

当我从第一页转到第二页时,一切正常。当我在 Chrome 中单击后退按钮时,原始页面呈现为 JSON 而不是 HTML。如果我在浏览器中点击刷新,我会得到 HTML 表示而不是 JSON。

这是我用来检测 JSON 与 HTML 的代码:

res.result.map { group =>
  render {
    case Accepts.Html() => Ok(views.html.groups.details(group))
    case Accepts.Json() => Ok(Json.toJson(group))
  }
}.getOrElse(NotFound)

这是此模式的标准实现,它适用于任何地方,除非我在某些情况下使用 Chrome 中的后退按钮。

是否有一些我没有清除的值,或者我的页面使用 Ajax 所做的事情让 Play 混淆以使其在 Json 中呈现,或者 Chrome 正在缓存页面但缓存了错误的接受标头?

我可以通过使用两种不同的路线来解决这个问题,一种用于 Json,另一种用于 Html,但我不喜欢这样,因为感觉就像我要放弃了。

有人对仅在后退按钮中导致此行为的原因有任何想法吗?

4

2 回答 2

23

凯文你是对的。但是,还有另一种解决方案。

如果您在响应头中添加“Vary: Accept”,它将使 chrome 和其他存在此问题的浏览器(例如 Firefox v 21)区分 json 和 html 缓存。注意:变化:Accept-Encoding 标头不起作用,据我测试。

如果你使用 nginx,你可以这样设置:http ://wiki.nginx.org/HttpProxyModule#proxy_set_header

proxy_set_header Vary Accept;

但是,nginx 存在一个问题,有时不会发送可变接受标头,这与缓存有关。见http://wiki.nginx.org/HttpProxyModule#proxy_set_header要处理这个,你可以为 nginx 开启 gzip_vary,但这会发送 Vary: Accept-Encoding 头。此标头不能解决问题。

我使用rails,并且在我修改的地方使用了一个before_filterresponse.headers["Vary"]= "Accept"

我敢肯定还有其他方法可以与其他服务器/框架一起使用。

更多信息:https ://web.archive.org/web/20130114082345/http://blog.sdqali.in/blog/2012/11/27/on-rest-content-type-google-chrome-and-caching /

于 2013-06-18T08:15:25.850 回答
2

这绝对是 Chrome 的浏览器缓存。它不区分使用“Accept”->“application/json”向 /foo/bar 发出的请求和使用常规 HTML 接受标头的请求。结果,我将加载 HTML 页面,该页面上的 JavaScript 将针对原始 JSON 数据访问相同的 URL,然后下次我回击时,Chrome 将提供缓存的 JSON 而不是缓存的 HTML。

结果,我不得不修改我的路由,以便我的 JSON/REST API 都通过不同的 URL,这样 Chrome(和 Safari)就不会缓存 JSON。

于 2013-05-24T12:16:36.790 回答