Rack中间件执行顺序疑问:为何后置use的中间件先执行?
Rack中间件执行顺序疑问
我在理解Rack中间件执行顺序时,写了如下Middleware1中间件:
class Middleware1 def initialize(app) @app = app end def call(env) puts "Middleware 1 start" status, headers, body = response = @app.call(env) puts "Middleware 1 to return" response end end
之后在主应用代码里,我把run MyApp.new写在use Middleware1前面:
require_relative "lib/middleware1" class MyApp def call(env) puts "main calling" [200, {}, ["Hello World"]] end end run MyApp.new use Middleware1
我本来以为主应用返回后这个中间件不会执行,但实际日志显示Middleware1先被调用:
Middleware 1 start main calling Middleware 1 to return
请问为什么Middleware1会先执行?有什么特定原因吗?
原因解析
- Rack中间件栈的构建规则:Rack是按代码中
use和run的书写顺序反向构建处理栈的——run语句定义的是整个栈的最内层(最终要执行的主应用),之后每写一个use,就会把对应的中间件包裹在当前栈的外层。也就是说,后写的use会成为请求进入时第一个被触发的中间件。 - 你的代码执行逻辑:
- 先执行
run MyApp.new,此时Rack的处理栈底层是MyApp; - 再执行
use Middleware1,Middleware1会被包裹在MyApp的外层,形成Middleware1 -> MyApp的栈结构; - 请求到达时,先触发外层的Middleware1的
call方法,打印"Middleware 1 start"; - 接着Middleware1调用
@app.call(env),这里的@app就是内层的MyApp,所以MyApp的call执行,打印"main calling"并返回响应; - 响应回到Middleware1的
call方法,打印"Middleware 1 to return",最后把响应返回给客户端。
- 先执行
- 如果想让中间件在主应用之后执行响应逻辑:只需把
use Middleware1放在run MyApp.new前面,此时Middleware1会被放在MyApp的内层,请求先到MyApp,响应返回时才会经过Middleware1的后续逻辑。
内容的提问来源于stack exchange,提问作者Dedy Puji
相关产品推荐
相关产品推荐

