Rack:Ruby Web服务器的瑞士军刀

131 阅读2分钟

Rack:Ruby Web服务器的瑞士军刀

Rack是什么?

Rack为使用Ruby开发Web应用程序提供了一个最小化、模块化且可适应的接口。它作为Web服务器和Web应用程序之间的标准接口,允许开发者无缝地使用不同的Web服务器和框架。

Rack应用

要使用Rack运行应用服务,你可以使用rackup命令,这是一个启动Web服务的强大工具。以下是如何实现一个简单的Web服务:

class Hello
  def call(env)
    [200, {"Content-Type" => "text/html"}, ["你好!"]]
  end
end

将这段代码保存在一个文件中,比如config.ru,然后你可以使用rackup启动服务器。

Rack应用结构

Screenshot 2024-09-07 at 21.48.34.png

Screenshot 2024-09-07 at 21.48.27.png 以下是组件如何相互作用的可视化表示:

状态图
    方向 TB
    config.ru --> Rackup
    Rackup --> Rack
    Rackup --> Webrick
    Rackup --> Puma

    Rack --> Rails
    Rack --> Sinatra
    Rack --> Hanami

数据流

Rack应用程序中的数据流很简单:

mermaid-diagram-2024-09-07-203537.png

状态图
    方向 LR
    [*] --> 请求
    请求 --> Rackup
    状态 Rackup {
        方向 LR
        Webrick --> Rack
        Rack --> 应用
    }

调用序列

Rack应用程序中请求处理的顺序:

序列图
    盒子 green HTTP服务器
    参与者 WH 作为 WEBrick::HTTPServer
    结束
    参与者 RHW 作为 Rackup::Handler::WEBrick
    盒子 rgb(33,66,99) Rack中间件
    参与者 RC 作为 Rack::ContentLength
    参与者 RCL 作为 Rack::CommonLogger
    参与者 RL 作为 Rack::Lint
    结束
    盒子 Blue应用
    参与者 Hello
    结束

    WH->>WH: 运行(socket)
    WH->>WH: 服务(请求, 响应)
    WH->>RHW: 服务(请求, 响应)
    RHW->>RC: 调用(env)
    RC->>RCL: 调用(env)
    RCL->>RL: 调用(env)
    RL->>Hello: 调用(env)

    Hello->>RL: [状态, 头部, 正文]
    RL->>RCL: [状态, 头部, 正文]
    RCL->>RC: [状态, 头部, 正文]
    RC->>RHW: [状态, 头部, 正文]
    RHW->>WH: [状态, 头部, 正文]

启动

启动过程涉及多个步骤,从Rackup::Server.start开始,到使用中间件构建应用程序堆栈。

运行应用

使用Rack::Builder#run方法来运行应用程序:

Rack::Builder#run(app=#<Hello:0x000000011e0d49d0>, block=nil)

应用俄罗斯套娃

Screenshot 2024-09-07 at 21.48.54.png

Rack应用程序可以与中间件嵌套,创建一个“俄罗斯套娃”结构:

def build_app(app)
  middleware[options[:environment]].reverse_each do |middleware|
    klass, *args = middleware
    app = klass.new(app, *args)
  end
  app
end

中间件

Rack中的中间件可以被看作是一系列层次:

状态图-v2
    状态 ContentLength {
        状态 CommonLogger {
            状态 Lint {
                Hello
            }
        }
    }

默认中间件

Rack附带了一系列默认中间件,可以在不同环境中使用:

def default_middleware_by_environment
  m = Hash.new {|h, k| h[k] = []}
  m["deployment"] = [
    [Rack::ContentLength],
    logging_middleware,
    [Rack::TempfileReaper]
  ]
  m["development"] = [
    [Rack::ContentLength],
    logging_middleware,
    [Rack::ShowExceptions],
    [Rack::Lint],
    [Rack::TempfileReaper]
  ]
  m
end

服务器

服务器可以使用Rackup::Handler进行配置和启动:

def server
  @_server ||= Handler.get(options[:server]) || Handler.default
end

WEBrick类用于处理服务器端操作:

模块 Rackup
  模块 HandlerWEBrick < ::WEBrick::HTTPServlet::AbstractServlet
      def self.run(app, **选项)
        ...
        @server = ::WEBrick::HTTPServer.new(选项)
        @server.mount "/", Rackup::Handler::WEBrick, app
        如果给定块 yield @server
        @server.start
      end
    end
  end
end

结论

Rack以其简单灵活的设计,允许开发者轻松地在Ruby中构建Web应用程序。无论你是使用Rails、Sinatra还是任何其他框架,Rack都提供了一个一致的接口来处理请求和响应。链式中间件的能力以及设置Web服务器的简单性,使Rack成为Ruby Web开发者工具箱中不可或缺的工具。