优雅地处理Rails 4中的InvalidAuthenticityTokenexception

我刚刚将一个应用程序从Rails 3升级到Rails 4,我看到一堆InvalidAuthenticityTokenexception弹出。 挖掘它看起来我们的用户在我们的网站上打开多个长期标签是相当普遍的。 所以我认为发生的事情是这样的:用户Alice打开了三个标签,她的会话过期了。 她重新登录其中一个选项卡,这会更新存储在其会话中的真实性令牌。 然后她返回到其他一个打开的选项卡并尝试提交数据,但她从我们引发的InvalidAuthenticityToken错误中得到500错误。

为Alice做一些error handling显然很好,所以她没有得到500错误。 我想知道这种情况的最佳做法。 从过期的标签处理Alice的提交有什么好方法? 我不想让当前会话到期,因为从用户的角度来看这会非常烦人(“我刚刚登录,你笨蛋!”)。 理想情况下,我只是希望用户重新加载页面,这将导致表单中存在正确的真实性令牌。 或者我应该做一些不同的事情,以便打开的长期标签注意到会话已经过期并强制重新加载? 从用户的角度来看,这可能是次优的,因为他们喜欢准备好该页面并且易于访问以便继续引用,这就是为什么他们首先在选项卡中将其打开。

该问题的解决方案可分为两个阶段。 第1阶段解决了ActionController::InvalidAuthenticityToken错误的问题,第2阶段处理了等待空闲的长标签的问题。

第1阶段(第1次变更)

一种方法是在错误发生之前将用户重定向回其位置。 对于前者 如果Alice有3个标签打开,第一个标签过期,Alice再次登录,因为她正在浏览它。 但当她移动到具有URL“ http://example.com/ex ”的标签3并提交表单时。 现在,我们可以将其重新定向到“ http://example.com/ex ”,而不是向她显示错误,并将已提交的表单值预先填写在表单中,以方便使用。

这可以通过以下方法实现:

1) ApplicationController – 添加此function:

 def handle_unverified_request flash[:error] = 'Kindly retry.' # show this error in your layout referrer_url = URI.parse(request.referrer) rescue URI.parse(some_default_url) # need to have a default in case referrer is not given # append the query string to the referrer url referrer_url.query = Rack::Utils.parse_nested_query(''). merge(params[params.keys[2]]). # this may be different for you to_query # redirect to the referrer url with the modified query string redirect_to referrer_url.to_s end 

2)您需要为所有表单字段包含默认值。 它将是该领域的名称。

 ... <% f.text_field, name: 'email', placeholder: 'Email', value: params[:email] %> ... 

这样,每当Alice提交一个带有错误的authenticity_token的表单时,她将被重定向回她的表单,并提供她提交的原始值,并且将显示一条闪回消息,请您重试您的请求。

第1阶段(第2变化)

另一种方法是将Alice重定向回她提交的表单,而不提供任何预先填充的值。

这种方法可通过以下方式实现:

1) ApplicationController – 添加此function:

 def handle_unverified_request flash[:error] = 'Kindly retry.' redirect_to :back end 

阶段2

为了解决期待已久的标签问题,您可以借助SSE的帮助。 Rails 4有ActionController::Live用于处理SSE。

1)将其添加到任何控制器:

 include ActionController::Live ... def sse response.headers['Content-Type'] = 'text/event-stream' sse = SSE.new(response.stream, retry: 2000, event: 'refresh') # change the time interval to your suiting if user_signed_in? # check if user is signed-in or not sse.write('none') else sse.write('refresh') end ensure sse.close end 

2)在路由文件中给上面的函数一个GET路由。 让这条路线叫’/ sse’

3)在你的布局中添加:

 <% if user_signed_in? %> # check if user is signed-in or not  <% end %> 

注意:并非所有浏览器都支持使用EventSource 。 请查看浏览器兼容性部分 。

来源: rails 4使用新的params和MDN 重定向 :使用服务器发送的事件

在我的rails 4.1.1应用程序中我遇到了同样的问题。 我通过将此代码添加到ApplicationController来解决它。 我在这里找到了解决方案。

 rescue_from ActionController::InvalidAuthenticityToken, with: :redirect_to_referer_or_path def redirect_to_referer_or_path flash[:notice] = "Please try again." redirect_to request.referer end 

这样,任何从ApplicationControllerinheritance的控制器都会处理错误,并通过flash消息重定向提交表单的页面,以便为用户提供错误指示。 请注意,这使用Ruby 1.9中引入的哈希语法。 对于旧版本的Ruby,您需要使用:with => :redirect_to_referer_or_path