【发布时间】:2021-09-10 15:50:16
【问题描述】:
我不需要这个功能,只是出于好奇。
我知道中间件在每个请求之前运行。
但是,期望中间件在每个请求之后运行是否合理?
如果是这样,我们该怎么做呢?
如果不是,logger中间件如何报告对请求的响应?
【问题讨论】:
-
我认为Guide 提供了一个相当全面的默认中间件,它如何工作、何时触发以及如何添加额外的中间件
-
是的,中间件同时处理请求和响应
我不需要这个功能,只是出于好奇。
我知道中间件在每个请求之前运行。
但是,期望中间件在每个请求之后运行是否合理?
如果是这样,我们该怎么做呢?
如果不是,logger中间件如何报告对请求的响应?
【问题讨论】:
在 Rails 中,中间件排列在一个堆栈中(您可以认为这个堆栈是一个管道),请求和响应向两个相反的方向扔堆栈。
rails 中间件堆栈
$ rails middleware
request # ... ^
| use Rack::ETag |
| use Rack::TempfileReaper |
| use Warden::Manager |
| run Bookstore::Application.routes response
V
为了将堆栈中的这些中间件链接在一起,较高的中间件会递归调用较低的中间件,让我们看一些代码来了解它是如何工作的,假设我们有 2 个中间件 m1 和 m2,其中 m1 排列在 m2 的正上方堆栈,然后是请求和响应的流程,如下所示抛出 m1、m2(步骤按顺序 [1]、[2]、...):
class M1
def initialize(app)
@app = app
end
def call(env) # [1] higher middleware call
# [2] before call recursive
# you could get request
request = ActionDispatch::Request.new env
# log request , or something else ...
status, headers, body = \ # [9] get response from M2
@app.call(env) # [3] call recursive M2
# log response, or do something else ...
[status, headers, body] # [10] return response to higher middleware
end
end
class M2
def initialize(app)
@app = app
end
def call(env) # [4] M1 call
# [5] before call recursive lower middleware
# same as above
status, headers, body = \ # [7] get response from lower middlewares
@app.call(env) # [6] call recursive lower middleware
# log response, or do something else ...
[status, headers, body] # [8] return response to M1 above
end
end
而最底层的中间件是 Rails 应用,所以调用栈看起来像一条链
call( ... call( ... call( ... rails_app.call() ))..)
因此您可以通过在此链中添加/插入_之前(之后)/删除节点来更改应用行为(或您的应用处理请求/响应的方式),非常灵活!!!
【讨论】: