Rails 没有在 ajax 帖子上重新加载会话

Posted

技术标签:

【中文标题】Rails 没有在 ajax 帖子上重新加载会话【英文标题】:Rails not reloading session on ajax post 【发布时间】:2011-07-04 20:18:05 【问题描述】:

我在使用 jQuery 的 Rails 和 ajax 方面遇到了一个非常奇怪的问题(尽管我认为这不是 jQuery 特有的)。

我的 Rails 应用程序使用 cookie 会话存储,并且我有一个非常简单的登录,可以在会话中设置用户 ID。如果会话中未设置 user_id,它会重定向到登录页面。这没有问题。 JQuery GET 请求也可以正常工作。问题是当我执行 jQuery POST 时 - 浏览器发送会话 cookie 正常(我通过 Firebug 确认了这一点并将 request.cookies 转储到日志)但会话为空白,即会话为 。

我在我的 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 帖子没有。

我们将不胜感激任何尝试解决此问题的帮助!

非常感谢, 戴夫

【问题讨论】:

【参考方案1】:

我将回答我自己的问题,因为我已经设法弄清楚发生了什么。我会把它贴在这里,以防它对其他人有用!

在进一步调查后,我发现应该使用 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 现在它只是悄悄地重置会话。

所以要在标头中发送令牌,您必须这样做(非常感谢this marvellous blog post):

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

现在一切正常。哪个不错。

【讨论】:

【参考方案2】:

我发现了另一个案例:

您是否在应用程序布局文件中设置了“csrf_meta_tag”?

在我的情况下,我没有设置该标签,并且遇到了同样的问题。

在 app/views/layouts/application.html.erb 中设置 csrf_meta_tag 后,一切正常!

最后,谢谢你帮我找到了根本原因!非常感谢~

【讨论】:

【参考方案3】:

这就是 official jquery-ujs rails adapter 在 3.0 系列中的用途。不过,您必须记住在升级 rails 版本时保持更新。

对我来说,从 3.0.3 升级到 3.0.8.rc4 还意味着从链接的 repo 手动获取 src/rails.js 文件。

由于 Rails 3.1 最终切换到 jQuery,未来在更新 rails(并使用 3.1 的内置资产管道)时应该通过 jquery-rails gem 自动更新

【讨论】:

【参考方案4】:

如果您在将csrf_meta_tag 正确发送到服务器后仍然有问题。确保您的会话存储配置正确。

如果:secure 在您的session_store.rb 中设置为true,则cookie(会话)将不会传输到您的http 服务器。文档:https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html

【讨论】:

以上是关于Rails 没有在 ajax 帖子上重新加载会话的主要内容,如果未能解决你的问题,请参考以下文章

获取向 Rails 服务器发出请求的 API

使用 AJAX 在 Rails 上加载 CSRF 令牌

Rails 仅在生产时才在页面重新加载时丢失会话变量 current_user_id(React 16.13、Rails 6、Heroku)

Rails 控制器方法在 Ajax 调用后不重新加载页面

CSS在检索帖子时没有样式,rails jquery

Grails Spring Security - 会话超时后重新登录时重新加载会话变量