You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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会成为请求进入时第一个被触发的中间件。
  • 你的代码执行逻辑:
    1. 先执行run MyApp.new,此时Rack的处理栈底层是MyApp;
    2. 再执行use Middleware1,Middleware1会被包裹在MyApp的外层,形成Middleware1 -> MyApp的栈结构;
    3. 请求到达时,先触发外层的Middleware1的call方法,打印"Middleware 1 start";
    4. 接着Middleware1调用@app.call(env),这里的@app就是内层的MyApp,所以MyApp的call执行,打印"main calling"并返回响应;
    5. 响应回到Middleware1的call方法,打印"Middleware 1 to return",最后把响应返回给客户端。
  • 如果想让中间件在主应用之后执行响应逻辑:只需把use Middleware1放在run MyApp.new前面,此时Middleware1会被放在MyApp的内层,请求先到MyApp,响应返回时才会经过Middleware1的后续逻辑。

内容的提问来源于stack exchange,提问作者Dedy Puji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 06:15:07