我们的团队最近提出了一个最初的边缘案例问题,当用户从具有某种javascript渲染的页面(无论是Ajax,标签等)中单击浏览器的后退按钮时,将显示原始javascript。要重新创建,我们按照以下步骤操作:
前面的步骤将显示:
(function() {
$(".job_applications").html("<li class=\"job_posting_application\">\n
...
...
...
...
);
}).call(this);
在一些命中或未命中的情况下,您不需要在返回上一页之前单击选项卡,但它仍然会呈现原始javascript。在一天结束时,似乎最后渲染的模板正在被缓存,这在浏览器的部分是正常的和预期的,但导致我认为是一个更大的问题。
Rails指南在Layouts and Rendering部分中说明,特别是关于模板的MIME类型:
默认情况下,Rails将使用MIME内容类型text / html(或者application / json,如果使用:json选项,或者application / xml用于:xml选项)提供渲染操作的结果)。
根据Rails默认值,我们的控制器的索引操作应该呈现我们的index.html.slim
模板。但是,当在拖尾服务器日志的同时对该页面进行非远程调用(例如,直接导航到浏览器中的页面)时,我们注意到它实际呈现index.js.coffee
。以下是我们的控制器操作,请注意我们没有明确响应html或js格式,因为我们可能应该考虑此页面中的重叠功能:
def index
@company_id, @division_id, @job_posting_id = params[:company_id], params[:division_id], params[:job_posting_id]
# API requests are made here to instantiate @job_posting, et al.,
# but are not shown for brevity
authorize! :manage, @job_posting
@survey = @job_posting.survey
@job_applications = @job_posting.job_applications(sort_column, sort_direction)
end
但是,根据此设置,{/ 1}} 应基于Rails默认值进行渲染。添加index.html.slim
块时,缓存似乎仍然有效,控制器可能不关心respond_to
块的存在:
respond_to
即使明确地,虽然有点臭,告诉每种格式呈现不同的模板,但def index
...
...
respond_to do |format|
format.html
format.js
end
end
模板似乎优先于js.coffee
模板:
html.slim
在上面的情况下,直接导航到浏览器中的页面(换句话说,不进行远程Ajax调用),服务器日志将呈现def index
...
...
respond_to do |format|
format.html { render template: "users/job_posting_applications/index" }
format.js { render template: "users/job_posting_applications/ajax" }
end
end
,即使Rails默认为html,除非另有说明
所有这些都说,以下是其他一些发现:
ajax.js.coffee
( 您可以参考上面显示的整个请求in this pastie )
为什么它作为JSON处理超出了我的考虑,考虑到我们没有在此请求上提供任何JSON,并且没有针对此路由的默认格式Started GET "/users/companies/1/divisions/18/job_postings/349421/applications" for 127.0.0.1 at 2012-10-03 19:55:26 -0400
Processing by Users::JobPostingApplicationsController#index as JSON
的路由规范。
此外,在此操作中调试:json
的值时,它会返回request.format
。
提供的另一个方案是在另一个仅包含application/json
模板的控制器(users/company_admin_metrics#index
)内。导航到此页面时,服务器日志显示它在index.html.slim
内呈现users/company_admin_metrics/index.html.slim
。当我创建一个空白的js.coffee模板时:
layouts/users
并直接导航到该索引页面,服务器日志显示它呈现$ touch app/views/users/company_admin_metrics/index.js.coffee
,这进一步暴露了有关模板呈现优先级的潜在问题。
是否有人遇到类似的问题可能会为此提供潜在的解决方法?
以下是这个特定问题的基本参与者的一小部分清单:
此请求取决于通过解析JSON并返回Ruby对象的客户端gem对我们的作业发布API的请求,但这些请求不会与此特定应用程序耦合,从而导致 this app为上述请求提供内容类型users/company_admin_metrics/index.js.coffee
。
答案 0 :(得分:9)
我认为您需要将格式扩展名.js
附加到您的ajax请求中的网址。
可能发生的情况是,用户正在index
点击/job_applications
操作并发出GET
html请求。然后ajax正在点击相同的URL /动作但请求javascript。当用户单击后退按钮时,浏览器无法区分两者之间的差异,因此使用最新的(javascript响应)。
答案 1 :(得分:4)
自问这个问题以来已经有好几个月了,但是自从遇到这个问题以后,我就开始给我两分钱。
正如carbo所说,浏览器可以告诉html和js请求之间的区别,所以当单击后退按钮时,它会看到相同的url,只是提供了js代码中发生的缓存数据。我有一些问题,但使用推送状态javascript修改ajax请求的浏览器历史记录。我发现最简单的解决方案是告诉浏览器不要缓存请求。因此,当回到上一页时,它被迫重新加载它。
您可以全局禁用缓存: $ .ajaxSetup({cache:false});
或者您可以尝试在特定的ajax请求上指定缓存false。
答案 2 :(得分:4)
最近在使用Rails 4.2.4的Chrome中开始看到这个问题。似乎是一个众所周知且备受争议的问题。我们的团队通过向Vary
次请求添加xhr
标头来解决此问题:
class ApplicationController < ActionController::Base
after_action :set_vary_header
private
# Fix a bug/issue/by-design(?) of browsers that have a hard time understanding
# what to do about our ajax search page. This header tells browsers to not cache
# the current contents of the page because previously when someone filtered results,
# went to the listing's external site, then hit Back, they'd only see the last
# ajax response snippet, not the full listings page for their search.
#
# Heated multi-year discussion on this issue in Chrome
# https://code.google.com/p/chromium/issues/detail?id=94369
#
# And continued by the Rails team:
# https://github.com/rails/jquery-ujs/issues/318
# https://github.com/rails/jquery-rails/issues/121
def set_vary_header
if request.xhr?
response.headers["Vary"] = "accept"
end
end
end