@app.call(env) 到底做了什么?
What does @app.call(env) really do?
我真的很喜欢了解这些东西在引擎盖下是如何工作的,尤其是在技术方面。目前,我正在更深入地研究 ruby 并尝试仅将它与 rack 一起使用,以了解基于 rack 的框架的工作原理。
此时此刻,机架中间件让我抓狂。为什么?虽然中间件很简单,但我对@app.call(env)
有点困惑。为了清楚起见,请考虑以下代码:
class MyCustomMiddleware
def initialize(app)
@app = app
end
def call(env)
@app.call(env) if env['REQUEST_METHOD'] != 'POST'
body = env['rack.input'].clone
body = JSON.parse(body.gets || {}, symbolize_names: true)
body[:some_message] = "Peace, Love and Hope"
env.update('rack.input', StringIO.new(JSON.dump(body)))
@app.call(env)
env
end
如果(且仅当)请求方法是 POST
,我想做的就是更改请求正文。如果请求方法是 "POST" 以外的任何其他类型,我想将请求传递给下一个中间件(它在 Rack 中以这种方式工作,对吗?)。问题是所有代码都在执行,无论请求方法是否为 POST
。
可能是对机架中间件的误解,因为我习惯于使用Express.js
。在 Express
中,你有一堆中间件,请求在其中传递,并且每个中间件调用 next()
方法以 "release" 请求。我在想 @app.call(env)
会类似于 Express
' next()
方法......但看起来不像,因为当我调用它时请求没有被释放并且所有代码都是正在执行。
谁能解释一下这个方法的真正作用并指出我的错误在哪里?
@app.call
不会终止处理程序的执行 - 它只是调用链中的下一个中间件。预计每个中间件将调用链中的下一个和 return 它的 return 值,或者通过 returning 一个 [status_code, body, headers]
的数组来终止链。每个中间件都应该通过 return 从其 #call
方法中提取该值,将 [status_code, body, headers]
的数组传回到链中。回想一下,在 Ruby 中,每个方法的最后一条语句的 return 值隐式 returned 给它的调用者。
正如所写,您将调用堆栈中剩余的中间件,然后丢弃其结果,然后继续您的处理程序,运行代码,调用剩余的中间件堆栈再次,最后return返回上游。
如果您想退出处理程序,只需明确 return
:
def call(env)
return @app.call(env) if env['REQUEST_METHOD'] != 'POST'
body = env['rack.input'].clone
body = JSON.parse(body.gets || {}, symbolize_names: true)
body[:some_message] = "Peace, Love and Hope"
env.update('rack.input', StringIO.new(JSON.dump(body)))
@app.call(env)
end
有条件地 运行 你的修改器可能更清楚,然后总是 @app.call
终止处理程序:
def call(env)
mutate!(env) if env['REQUEST_METHOD'] == "POST"
@app.call(env)
end
def mutate!(env)
body = env['rack.input'].clone
body = JSON.parse(body.gets || {}, symbolize_names: true)
body[:some_message] = "Peace, Love and Hope"
env.update('rack.input', StringIO.new(JSON.dump(body)))
end
由于 @app.call
是此处 #call
中的最后一条语句,它的 return 值被 return 发送给中间件的调用者。
我真的很喜欢了解这些东西在引擎盖下是如何工作的,尤其是在技术方面。目前,我正在更深入地研究 ruby 并尝试仅将它与 rack 一起使用,以了解基于 rack 的框架的工作原理。
此时此刻,机架中间件让我抓狂。为什么?虽然中间件很简单,但我对@app.call(env)
有点困惑。为了清楚起见,请考虑以下代码:
class MyCustomMiddleware
def initialize(app)
@app = app
end
def call(env)
@app.call(env) if env['REQUEST_METHOD'] != 'POST'
body = env['rack.input'].clone
body = JSON.parse(body.gets || {}, symbolize_names: true)
body[:some_message] = "Peace, Love and Hope"
env.update('rack.input', StringIO.new(JSON.dump(body)))
@app.call(env)
env
end
如果(且仅当)请求方法是 POST
,我想做的就是更改请求正文。如果请求方法是 "POST" 以外的任何其他类型,我想将请求传递给下一个中间件(它在 Rack 中以这种方式工作,对吗?)。问题是所有代码都在执行,无论请求方法是否为 POST
。
可能是对机架中间件的误解,因为我习惯于使用Express.js
。在 Express
中,你有一堆中间件,请求在其中传递,并且每个中间件调用 next()
方法以 "release" 请求。我在想 @app.call(env)
会类似于 Express
' next()
方法......但看起来不像,因为当我调用它时请求没有被释放并且所有代码都是正在执行。
谁能解释一下这个方法的真正作用并指出我的错误在哪里?
@app.call
不会终止处理程序的执行 - 它只是调用链中的下一个中间件。预计每个中间件将调用链中的下一个和 return 它的 return 值,或者通过 returning 一个 [status_code, body, headers]
的数组来终止链。每个中间件都应该通过 return 从其 #call
方法中提取该值,将 [status_code, body, headers]
的数组传回到链中。回想一下,在 Ruby 中,每个方法的最后一条语句的 return 值隐式 returned 给它的调用者。
正如所写,您将调用堆栈中剩余的中间件,然后丢弃其结果,然后继续您的处理程序,运行代码,调用剩余的中间件堆栈再次,最后return返回上游。
如果您想退出处理程序,只需明确 return
:
def call(env)
return @app.call(env) if env['REQUEST_METHOD'] != 'POST'
body = env['rack.input'].clone
body = JSON.parse(body.gets || {}, symbolize_names: true)
body[:some_message] = "Peace, Love and Hope"
env.update('rack.input', StringIO.new(JSON.dump(body)))
@app.call(env)
end
有条件地 运行 你的修改器可能更清楚,然后总是 @app.call
终止处理程序:
def call(env)
mutate!(env) if env['REQUEST_METHOD'] == "POST"
@app.call(env)
end
def mutate!(env)
body = env['rack.input'].clone
body = JSON.parse(body.gets || {}, symbolize_names: true)
body[:some_message] = "Peace, Love and Hope"
env.update('rack.input', StringIO.new(JSON.dump(body)))
end
由于 @app.call
是此处 #call
中的最后一条语句,它的 return 值被 return 发送给中间件的调用者。