如何 运行 一个仅包含中间件的简单 Ruby Rack 应用程序?

How to run a simple Ruby Rack app that consists of only middleware?

我有一个简单的 Ruby Rack 应用程序,它只包含中间件。我真的不需要 "app",因为中间件可以完成我想要的一切。如何将我的 config.ru 定义为 运行 只有中间件作为应用程序?

require "some_middleware"
use SomeMiddleware
run -> {|env| [200, {"Content-Type" => "text/plain"}, ["I don't need this part!"]] }

Rack 应用程序(包括中间件)基本上只是一个响应 call 的对象,接受描述请求的散列并返回描述响应的数组。

当使用 rackup 文件时,Rack 使用 Rack::Builder. The run method just sets the “base” app:

中描述的 DSL
def run(app)
  @run = app
end

use 方法存储您要包含在您的应用程序中的中间件 classes,然后在构建最终应用程序时对每个中间件执行类似的操作(与它们的顺序相反)出现在 config.ru 文件中):

@run = MiddleWare.new(@run, other_args)

比这个稍微复杂一点,但这是大体思路。中间件 class 的新实例已创建,现有应用程序作为构造函数的第一个参数传递,生成的对象成为新应用程序。这是 Rack 中间件的(没有很好记录的)“接口”:它的初始化程序的第一个参数是它正在包装的应用程序,其余的是传递给 use.

的任何其他参数

DSL 期望总是有 runmap 语句,如果两者都省略,将会出现错误。

如果您的中间件是以这样一种方式编写的,它可以处理没有参数传递给它的初始化程序,并且它的行为就像一个完整的应用程序,那么您可以直接将它用作 [=19] 中的应用程序=]:

run SomeMiddleware.new

这就是 Sinatra 所做的,以允许它 used as middleware. It stores the app in the initializer if it is given, and then when a request arrives that doesn’t match any route it uses the presence of @app to decide whether to behave as middleware 并传递请求,或者作为最终应用程序并将其视为未找到的错误。

如果您的中间件没有这种灵活性,那么您将需要提供一个应用程序来包装它,就像您在示例中所做的那样。在这种情况下,如果中间件无法正确处理请求并尝试将其传递给包装的应用程序,则让应用程序进行错误处理也可能很有用。

如果您想避免在 config.ru 中使用单独的 userun 语句,您可以只使用 run,并将一个简单的应用程序直接传递给您的中间件:

run SomeMiddleware.new(->(e){
  [500, {'Content-type' => 'text/plain'}, ["Error: SomeMiddleware didn't handle request"]]
}

注意这是如何遵循上述中间件接口的:初始化程序的第一个参数是要包装的应用程序。