我有一个简单的Ruby Rack应用程序,它只包含中间件。我真的不需要“应用程序”,因为中间件可以完成我想要的任何事情。如何定义我的config.ru
仅将中间件作为应用程序运行?
require "some_middleware"
use SomeMiddleware
run -> {|env| [200, {"Content-Type" => "text/plain"}, ["I don't need this part!"]] }
答案 0 :(得分:2)
Rack应用程序(包括中间件)基本上只是一个响应call
的对象,接受描述请求的哈希并返回描述响应的数组。
使用rackup
文件时,Rack使用Rack::Builder
中描述的DSL。 run
method just sets the “base” app:
def run(app)
@run = app
end
use
方法存储您希望包含在应用中的中间件类,然后在构建最终应用时为每个应用执行类似的操作(与它们在{{1}中的显示方式相反的顺序文件):
config.ru
这比这复杂一点,但这是一般的想法。创建中间件类的新实例,将现有应用程序作为构造函数的第一个参数传递,结果对象成为新应用程序。这是Rack中间件的“没有详细记录”的“接口”:它的初始化器的第一个参数是它正在包装的应用程序,其余的是传递给@run = MiddleWare.new(@run, other_args)
的任何其他参数。
DSL期望始终存在use
或run
语句,如果省略两者,则会出现错误。
如果您的中间件是以这样的方式编写的,它可以处理没有传递给其初始化程序的参数,并且它的行为就像一个完整的应用程序,那么您可以直接将其用作map
中的应用程序:
config.ru
这就是Sinatra允许used as middleware做的事情。它stores the app in the initializer如果给出,然后当一个请求到达时与任何路由不匹配时它会使用@app
to decide whether to behave as middleware的存在并传递请求,或者表现为最终应用并对其进行处理作为一个未找到的错误。
如果您的中间件没有这种灵活性,那么您将需要提供一个应用程序来包装它,就像您的示例中所示。在这种情况下,如果中间件没有正确处理请求并尝试将其传递给包装的应用程序,那么让应用程序进行错误处理也是有用的。
如果您想避免在run SomeMiddleware.new
中使用单独的use
和run
语句,则可以使用config.ru
,并将一个简单的应用直接传递到您的中间件:
run
请注意这是如何遵循上面介绍的中间件接口的:初始化程序的第一个参数是要包装的应用程序。