middleware 本质就是 Rack app,只是简单封装了一下。
我们可以编写自己的 Middleware,用来处理 @app
和 env
.
举例一
放在 app/middleware/ 目录下,按照 middleware 写。然后在 config 里 use 就行了,不用做其它的配置。
class Scrubber
def initialize(app, options)
@app = app
@routes = options[:routes]
end
def call(env)
scrub(env)
@app.call(env)
end
private
def scrub(env)
return unless @routes.include?(env["PATH_INFO"])
rack_input = env["rack.input"].read
params = Rack::Utils.parse_query(rack_input, "&")
params["xml"] = Rack::Utils.unescape(params["xml"])
env["rack.input"] = StringIO.new(Rack::Utils.build_query(params))
rescue
ensure
env["rack.input"].rewind
end
end
然后:
# 注意,这里直接引用相关类
config.middleware.insert_before ActionController::ParamsParser,
"Scrubber",
:routes => [ "/examples/scrubbed" ]
举例二
放在 lib/ 目录下,按照 middleware 写。然后在 config 里 use 就行了,不用做其它的配置。
class ResponseTimer
def initialize(app, message = "Response Time")
@app = app
@message = message
end
def call(env)
dup._call(env)
end
def _call(env)
@start = Time.now
@status, @headers, @response = @app.call(env)
@stop = Time.now
[@status, @headers, self]
end
def each(&block)
if @headers["Content-Type"].include? "text/html"
block.call("<!-- #{@message}: #{@stop - @start} -->\n")
end
@response.each(&block)
end
end
然后:
# 注意,这里以字符串的方式引用
config.middleware.use "ResponseTimer", "Load Time"
参考