Rack简单使用以及Header小坑

由于需要对Ruby的API项目写个全局过滤的东西,为了不从业务上修改太多代码,因此最好的方案是去用到中间件这个玩意。

Ruby的Rack,基本已成Ruby中服务器公共的规范,因此写一个简单Rack中间件,基本能在所有的Ruby服务器中进行使用。

我对基本实现原理就不讲解了,百X, 谷X,随便看。这里,只对Rack中间件实现进行个简易说明,例子如下:

class RackMiddleware
  def initialize(app)
    @app = app
  end
  def call(env)
    #before run code
    status, header, body = @app.call(env)
    #after  run code
    [ status, header, body ]
  end
end

初始化 initialize 时会传入一个app参数,实际上,这个app参数是绑定的中间件的实例,他们将会一层一层进行绑定, 当执行时,依次有序调用call方法,然后将完成的数据已约定的格式进行返回。其中env参数中,包含了请求的各种信息及参数, 因此,你需要通过call的上下文去增添自己需要的代码。

说简单点,就是个洋葱模型的中间件。

但是,在Rack中,关于header信息,有一个小坑。

所有的自定义头信息在进入RACK后都会进行一个规范化处理,比如:

 //这里包含了一个乱七八糟的header名字
 curl -H "HUA-Niao_feng-YUE: xxx" http://xxxx.xxxx.xxx  

在Rack中,它将此自定义header存入env时,将进行一个强制转换(转换方式请直接看源码),在env参数中获取此头,则需要写成

  env["HTTP_HUA_NIAO_FENG_YUE"]

这样,它将你设置的头完全给改了个样式进行中间件的传递,这和原始的名字是有却别的,也因此你在中间件时候要获取自定义header时, 无法去直接使用本身的header名。

当然,上面是在原始的env传递的参数时的形态(调用call之前),在中间件call的链条中,最终它也会返回一个处理后的header格式(call之后)

  status, header, body = @app.call(env)    #env["HTTP_HUA_NIAO_FENG_YUE"]
  header["Hua-Niao-Feng-Yue"]   

总的来说,Rack已约定的形式,控制规范了整个请求中Header的获取方式。在实际使用时,你不用担心对方传的header是否是大写还是小写,是_还是-, 当然,缺点也很明显,别人直接复制一个头给你,你直接粘贴上去,经常会发现根本找不到。。。。

评论