我刚刚将一个应用程序从Rails 3升级到Rails 4,并且看到一堆InvalidAuthenticityToken异常 pop 。挖掘它看起来很常见,对于我们的用户来说,在我们的网站上打开多个长期存在的标签页是很普遍的。因此,我认为正在发生的事情是这样的:用户Alice打开了三个选项卡,并且她的 session 已过期。她重新登录选项卡之一,该选项卡更新了存储在 session 中的真实性 token 。然后,她返回到其他打开的选项卡之一并尝试提交数据,但是她从我们提出的InvalidAuthenticityToken错误中得到了500错误。

对Alice进行一些错误处理显然很不错,这样她就不会收到500错误。我想知道这种情况下的最佳做法。从过期标签处理Alice提交的好方法是什么?我不想使当前 session 到期,因为从用户的 Angular 来看,这将非常烦人(“我刚刚登录,您真可恶!”)。理想情况下,我只希望用户重新加载页面,这将导致表单中存在正确的真实性 token 。还是我应该做些不同的事情,以使打开的长寿命选项卡会通知 session 已过期并强制重新加载?从用户的 Angular 来看,这可能不是最佳选择,因为他们喜欢准备好该页面并且可以轻松访问该页面以保持引用,这就是为什么他们首先在选项卡中将其保持打开状态的原因。

最佳答案

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

阶段1(第一个变化)

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

可以通过以下方法实现:

1) ApplicationController-添加此功能:

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] %>
...

这样,每当爱丽丝提交带有错误authenticity_token的表单时,她都会被重定向回具有提交的原始值的表单,并且将显示一条简短消息,请您重试您的请求。

第1阶段(第二个版本)

另一种解决方法是将Alice重定向回她提交的表单,而无需任何预先填写的值。

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

1) ApplicationController-添加此功能:
def handle_unverified_request
    flash[:error] = 'Kindly retry.'
    redirect_to :back
end

阶段2

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

1)将此添加到任何 Controller :
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
    <script>
        var evtSource = new EventSource("/sse");

        evtSource.addEventListener('refresh', function(e){
            if(e.data == 'refresh'){
                window.location = window.location.href;
            }
        });
    </script>
<% end %>



资源:
rails 4 redirect back with new paramsMDN: Using server-sent events

关于ruby-on-rails - 在Rails 4中优雅地处理InvalidAuthenticityToken异常,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36509300/

10-11 23:14
查看更多