Rails tips: 怪异的ActionController::InvalidAuthenticityToken 错误

简介:
序:
最近在做医疗相关的数据应用,知道治病要找到病因,才好对症下药,因为不同的病因,有可能引发相同的病症。而从症状入手确定病因,却也是最直接最常用的一个种诊断手法,但不能浮于表面现象,还要深入排查寻找病根才能真正根除疾病。

概述:
开始以为是 protect_from_forgery 引发的问题,但实际却是cgi接口的问题。由于“症状”只有在特定环境才会发生,在本地开发模式无法重现错误,更不用说调试,这才是最麻烦的地方。有BUG不怕,怕的是找不到BUG在哪。

正文:
具体“症状”表现为:
在production server中,有时在进行登录或表单提交操作时会出现异常提示:
ActionController::InvalidAuthenticityToken

异常抛出在:
/usr/local/lib/ruby/gems/1.8/gems/actionpack-2.3.4/lib/action_controller/request_forgery_protection.rb:79:in `verify_authenticity_token'


出错后刷新几次或者点击别的页面再重新提交问题消失不再出现。

因为只是简单的表单提交操作,因此并不是常见的ajax引发的InvalidAuthenticityToken 问题。即使把本地开发环境(apache+passenger,或者单个mongrel by script/server)切换到production 模式,并把production的数据在本地导入,都无法重现问题,似乎只在production server的运行环境(nginx + mongrel cluster)中才会出现。

要debug,肯定要找出bug所在,找出bug之前,就要确定bug出现的条件(现场重现)。

这个现象不是每次访问都出现,感觉像是“随机”出现,一时抓不到明确的规律。

不断测试后来发现问题出现的共通特点:是在本地提及了代码后,然后执行服务器自动更新命令(服务器自动更新代码、数据迁移、最后重启web server)后才出现的。再一步测试,确认了是重启web server后才出现问题,“随机”之谜破解。

有时按Ctrl+F5 强制刷新后问题消失,开始以为是浏览器的自动填充表单中的authenticity_token 导致的,但测试所有浏览器后(FF3,CHROME,IE8,SeaMonkey)都有同样现象。

反复测试,终于找出了问题重现的步骤:

1. 打开一个show 页面
2. 重启mongrel server
3. 在show页面进入编辑页面
4. 提交表单
5. 出现错误后,后退到编辑页,刷新(直接F5,或者Ctrl+F5强制刷新)后再提交,则不会出现报错
(或者在第4步中,刷新两次后再提交表单,则不会出现错误)

问题得以重现!接下来就可以开始debug了,但这情况debug有点麻烦。

多次查看HTML的源码,发现authenticity_token的值并没有变动(authenticity_token  这个值不是每次请求后都改变,而是在seesion的生命周期内有效)。

只好在test server(与production server完全一样的运行环境:nginx + mongrel cluster)中进行跟踪。
因为没办法确定bug的确切引发因数,也没办法使用debugger触发断点,只好插入logger来跟踪数据:
最接近异常的地方是 verified_request? 方法,因此在application_controller 中覆盖它并插入跟踪代码:

def verified_request?
logger.info("form_authenticity_token=#{form_authenticity_token}")
logger.info("params_token:#{params[request_forgery_protection_token]}")
logger.info("params:#{params.inspect}")

!protect_against_forgery?     ||
request.method == :get      ||
request.xhr?                ||
!verifiable_request_format? ||
form_authenticity_token == params[request_forgery_protection_token]
end

在verified_request?插入日志跟踪发现,重启mongrel后,提交的数据中POST的数据为空(params中只有记录到从 URL中获取到的数据如controller,action,而没有所提交的form数据),自然就无法通过 form_authenticity_token == params[request_forgery_protection_token] 这步判断。

这时推测原因可能是 mongrel进程 重启后,与nginx失去联系(虽然通讯端口不变),提交的数据由nginx接收到,但没有全部转发给mongrel (POST的数据丢失)

但查看nginx的日志时,却发现是有记录到post数据的长度(长度等于在Firebug中发送出去的数据长度),因此确定nginx是有接收到post的数据,但没有转发给mongrel(或者mongrel接收出错?)

至此,可以排除了是由 authenticity_token 相关代码导致的问题,而是nginx和mongrel的通信问题导致了问题出现,因此才无法在本地重现问题。

知道关键部分所在,很快就能google到 相关的问题  :
“   After you restart a Mongrel server the first request will always fail to have the correct HTTP request body. The reason for this is the override of CGI#initialize_query method by ActionController in the cgi_ext/query_extension.rb file.“

解决倒是简单:
“but the solution is easy: just require action_controller/cgi_ext.rb when ActionController loads.“

这里 有该问题详细的讲解。

最终使用的解决方案是:
添加启动补丁:
config/initializers/rails_patch.rb

内容为:
require 'action_controller/cgi_ext' if Rails::version == '2.3.4'

问题解决!(该问题会在Rails 2.3.5 中解决)




本文转自 fsjoy1983 51CTO博客,原文链接:http://blog.51cto.com/fsjoy/240417,如需转载请自行联系原作者
目录
相关文章
|
3月前
|
前端开发 JavaScript
JavaScript快捷方式:15个简写技巧,让你的代码事半功倍!
JavaScript快捷方式:15个简写技巧,让你的代码事半功倍!
|
3月前
|
C++
codeAction提供代码错误解决方案重要笔记
codeAction提供代码错误解决方案重要笔记
|
11月前
|
数据采集 iOS开发 MacOS
Bug or Feature?藏在 requests_html 中的陷阱
Bug or Feature?藏在 requests_html 中的陷阱
66 0
|
编译器 测试技术 Go
Go 语言入门很简单:技巧和窍门 (Tips and Tricks)
本节将随着时间的推移而增长,但主要目标是分享一些有经验的开发人员在一段时间内发现的技巧。希望这些技巧能让新用户更快地提高工作效率。
|
存储 JavaScript 前端开发
web前端学习(三十二)——JavaScript语法、语句输出及注释的相关设置
web前端学习(三十二)——JavaScript语法、语句输出及注释的相关设置
web前端学习(三十二)——JavaScript语法、语句输出及注释的相关设置
|
编译器 Shell 测试技术
Go 语言入门很简单--技巧和窍门(Tips and Tricks)
Go 语言入门很简单--技巧和窍门(Tips and Tricks)
152 0
Go 语言入门很简单--技巧和窍门(Tips and Tricks)
在sublime text里阅读ABAP源代码的一些例子
在sublime text里阅读ABAP源代码的一些例子
104 0
在sublime text里阅读ABAP源代码的一些例子
|
移动开发 前端开发 小程序
对CSS变量不熟悉,这4个事例可看看!
随着 Web应用程序变得越来越大,CSS变得越来越大,越来越冗长,而且混乱不堪。 在良好的上下文中使用CSS变量,可为我们提供重用和轻松更改重复出现的CSS属性的机制。
164 0
对CSS变量不熟悉,这4个事例可看看!
|
JavaScript 前端开发 开发者
10个JavaScript常见BUG及修复方法
译者按: JavaScript语言设计太灵活,用起来不免要多加小心掉进坑里面。 原文: Top 10 bugs and their bug fixing 译者: Fundebug 为了保证可读性,本文采用意译而非直译。
1036 0