最近刚做好一个站,rails 3,大家捧场看看,谢谢!www.yo945.com
SwfUpload相当的好用,在让我在写前台功能的时候,是相当的爽快,然后写后台,OK,相当相当的爽快,相当相当的给力,可同时上传N个文件,显示进度,上传完成支持回调,相当好用!可是,当我在给后台加上用户登录验证时,发现居然取不到session了?!无论如何也取不到!相当相当的郁闷了……
分析了一下,主要原因是因为Rails为了安全,启用了CSRF验证,而SwfUpload因为FLASH对于安全设置的要求,又不允许随意设置HTTP头,而且默认也是不加上cookie的,所以导致上传时没有cookie也没有session_id。
解决之道,就是要让SwfUpload带上该带的数据,又要让Rails通过验证,具体作法,记录如下。
首先,如果本次操作是必须要有cookie中带的信息的,那么先要让swfuplod带上cookie信息,这步不是必须的,看个人需要,做起来也是相当的简单,因为在下载下来的SWFUpload v2.2.0.1 Core中,本身就带了一个pluggin,就是plugins\swfupload.cookies.js,引用的时候先引用swfupload组件,再引用swfupload.cookie.js即可,不有再做任何额外操作,在提交时自动就会带上cookie信息。加上这个插件后,swfuplod多了一个方法,就是refreshCookies,功能么一看函数名就知道了。插件的原理很简单,就是读取document.cookie然后给swfupload的post_params设置值而已,所以如果嫌它写得麻烦,自己设置一下也是很简单的。
第二步,给post_params加上两个必须属性,这是关键一步。第一个参数,就是CSRF的值,第二个参数,就是session_id值。大致上,可以这样写,先通过服务器帮助,设置属性值给一个参数对象,然后在初始化的时候设置给post_params.
//这是CSRF那一长串字符
var _token = '<%=form_authenticity_token-%>';
//这是session_id值
var _session_id = '<%=cookie[Rails.application.config.session_options[:key]]-%>';
//这是session的名称,具体设置在config/initializers/session_store.rb里面
var _session_key = '<%-Rails.application.config.session_options[:key]%>';
//设置一个参数对象
var params = {
'authenticity_token':_token
}
params[_session_key] = _session_id
//如果有别的要提交的参数一一起设置了,然后设置给post_params
第三步,设置服务器端。
1.在app下,建立一个middleware文件夹,在里面建立一个中间件的ruby文件,名字随意,我这里叫flash_session_cookie_middleware.rb,事实上网上找来的资料里面都叫这名字,这出自国外一篇文章。代码如下:
require 'rack/utils' class FlashSessionCookieMiddleware def initialize(app, key='_fly84_session') @app = app @session_key = key end def call(env) if env['HTTP_USER_AGENT'] =~ /^(Adobe|Shockwave) Flash/ req = Rack::Request.new(env) env['HTTP_COOKIE'] = [ @session_key, req.params[@session_key] ].join('=').freeze unless req.params[@session_key].nil? #env['HTTP_ACCEPT'] = "#{req.params['_http_accept']}".freeze unless req.params['_http_accept'].nil? end @app.call(env) end end
2.加入配置
config/application.rb下,加入
config.autoload_paths += %W( #{Rails.root.to_s}/app/middleware )
config/initializers/session_store.rb中,加入
Rails.application.config.middleware.insert_before(Rails.application.config.session_store, FlashSessionCookieMiddleware, Rails.application.config.session_options[:key])
Rails.application.config.session_options[:key]就是在session_store里面设置的那个session的名字
好了,就这么多了,设置是挺简单的,原理也很容易理解,就是我自己也不明白,为什么会为了这个弄了N久。第一次弄的时候,连找资料,半小时就好了,然后有点小开心,喝了杯咖啡散了个步,结果再一测试就不行了,然后再找原因再改的,到最后也基本还是这样。但愿接下来顺利。