Rails在ajax请求中无法重新加载会话

62

我在Rails和jQuery下遇到一个非常奇怪的问题(尽管我认为这并不特定于jQuery)。

我的Rails应用程序使用cookie会话存储,并且我有一个非常简单的登录功能,它将用户ID设置在会话中。如果在会话中没有设置user_id,则重定向到登录页面。这是没有问题的。JQuery的GET请求也能正常工作。问题出现在我进行jQuery的POST请求时——浏览器会发送会话cookie(我用Firebug确认了这一点,并将请求.cookies转储到日志中),但会话是空的,即session is {}。

我在我的application.js中执行如下操作:

$(document).ajaxSend(function(e, xhr, options) {
  var token = $("meta[name='csrf-token']").attr('content');
  xhr.setRequestHeader('X-CSRF-Token', token);
});

这是我的示例文章:

$.post('/test/1', { _method: 'delete' }, null, 'json');

这应该到达这个控制器方法 (_method: delete):

def destroy
  respond_to do |format|
    format.json { render :json => { :destroyed => 'ok' }.to_json }
  end
end

通过查看日志和使用Firebug,我可以确认在ajax提交发生时正确的cookie值已发送到请求头部,但似乎在某个时刻Rails丢失了这个值,因此丢失了会话,所以它重定向到登录页面并永远无法达到该方法。

我已经尝试了我所能想到的一切来调试这个问题,但我现在越来越认为这可能是Rails中的一个错误。如果有帮助的话,我正在使用Rails 3.0.4和jQuery 1.5。我发现很奇怪的是常规的(即非ajax)get和post请求工作正常,ajax get请求也没有问题,只有ajax post请求出现问题。

任何帮助修复此问题的意见都将不胜感激!

非常感谢,
Dave

4个回答

114

我将回答自己的问题,因为我想出了原因。我会在这里发布它,以防对任何其他人有用!

进一步调查后,我发现本应该使用CSRF令牌设置请求头的代码没有起作用。这是原始代码:

$(document).ajaxSend(function(e, xhr, options) {
  var token = $("meta[name='csrf-token']").attr('content');
  xhr.setRequestHeader('X-CSRF-Token', token);
});

发生的情况是,这段代码没有设置头部信息。Rails收到了一个Ajax请求,但是令牌与会话不匹配,因此会重置会话。以前会引发ActionController::InvalidAuthenticityToken错误(如果引发了错误,我可能早就发现了...好吧),但自从Rails 3.0.4版本之后,它现在只是安静地重置了会话。

所以要在标头中发送令牌,您必须执行以下操作(感谢这篇精彩的博客文章):

$.ajaxSetup({
  beforeSend: function(xhr) {
    xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
  }
}); 

现在一切都按照预期工作了,这很不错。


6
我发现另一个情况:
你是否在应用程序布局文件中设置了“csrf_meta_tag”?
在我的情况下,我没有设置该标记,并遇到了与您相同的问题。
在app/views/layouts/application.html.erb中设置csrf_meta_tag后,一切正常!
最后,感谢您帮助我找到根本原因!非常感谢~

0

这就是3.0系列中official jquery-ujs rails adapter的作用。但在升级Rails版本时要记得及时更新。

对我而言,从3.0.3升级到3.0.8.rc4 还需要手动获取链接仓库中的src/rails.js文件。

由于Rails 3.1最终转向使用jQuery,在未来通过jquery-rails gem自动更新并使用3.1内置的asset pipeline就方便多了。


0
如果您在将csrf_meta_tag正确发送到服务器后仍然遇到问题,请确保您的会话存储配置是正确的。
如果在您的session_store.rb中将:secure设置为true,则cookie(会话)将不会传输到您的HTTP服务器。文档:https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接