文档章节

Rack 源码分析

邪云子
 邪云子
发布于 2014/08/28 17:04
字数 640
阅读 127
收藏 0

A Rack application is an Ruby object (not a class) that responds to call. It takes exactly one argument, the environment and returns an Array of exactly three values: The status, the headers, and the body.

  • status is the HTTP status code.
  • headers is a hash of HTTP headers for the response.
  • body is the actual body of the response (e.g. the HTML you want to display). The body must also respond to each.

安装 rack

$ gem install rack

irb 中运行

2.0.0-p353 :001 > require 'rack'
2.0.0-p353 :002 > Rack::Handler::WEBrick.run lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['success']] }

简单例子

$ mkdir hellorack && cd hellorack

Now create a file named config.ru and fill it in with the following:

class Hello
  def self.call(env)
    [ 200,                              # 200 indicates success
      {"Content-Type" => "text/plain"}, # the hash of headers
      ["Hello from Rack!"]              # we wrap the body in an Array so
                                        # that it responds to `each`
    ]
  end
end
 
# Tell Rack what to run our app
run Hello

Save the file, open up your terminal and run the rackup command:

$ rackup
[2012-12-21 17:48:38] INFO  WEBrick 1.3.1
[2012-12-21 17:48:38] INFO  ruby 1.9.2 (2011-07-09) [x86_64-darwin11.0.1]
[2012-12-21 17:48:38] INFO  WEBrick::HTTPServer#start: pid=1597 port=9292

更多使用实例

http://git.oschina.net/xieyunzi/ruby-snippet/tree/master/rack

rackup 执行流程

rack/bin/rackup.rb

require "rack"
Rack::Server.start

Rack::Server.start 可以通过传递参数,或是读取同级目录下的 config.ru 初始化 rack app,然后调用 rack server 的 run 方法启动 web server ,如下:

rack/lib/server.rb

module Rack
  class Server
    def self.start(options = nil)
    end

    def start(&blk)
      ...
      # 此处调用 Rack::Handler 实例
      server.run wrapped_app, options, &blk
    end
  end
end

rack 与 web server 的沟通中介 Rack::Handler

Rack::Handler::WEBrick 为例

module Rack
  module Handler
    class WEBrick < ::WEBrick::HTTPServlet::AbstractServlet
      def self.run(app, options={})
        ...
        @server = ::WEBrick::HTTPServer.new(options)
        @server.mount "/", Rack::Handler::WEBrick, app
        yield @server  if block_given?
        @server.start
      end

      def initialize(server, app)
        super server
        @app = app
      end

      # 实现 service
      def service(req, res)
        ...
        status, headers, body = @app.call(env)
        ...
      end
    end
  end
end

web server

webrick 为例

<!-- lang: ruby -->
require 'webrick'

options = {
  BindAddress: 'localhost',
  Port: 8080
}
server = WEBrick::HTTPServer.new(options)

begin
  server.start
ensure
  server.shutdown
end

调用流程

WEBrick::HTTPServer::new
-> WEBrick::GenericServer#start(&block)
-> WEBrick::HTTPServer#start_thread(sock, &block)
-> WEBrick::HTTPServer#run(sock)

WEBrick::HTTPServer

module WEBrick
    class HTTPServer < ::WEBrick::GenericServer
        def run(sock)
          while true
            ...
            server = lookup_server(req) || self
            ...
            server.service(req, res)
            ...
            res.send_response(sock)
            ...
          end
        end
    
        def service(req, res)
          ...
          servlet, options, script_name, path_info = search_servlet(req.path)
          ...
          si = servlet.get_instance(self, *options)
          ...
          si.service(req, res)
        end
    end
end

创建 Rack app, Rack::Builder

app = Rack::Builder.app do
  use Rack::CommonLogger
  run lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['OK']] }
end
run app

运行 Rack app, Rack::Server#start

Rack::Server.start app: app , Port: 3000

使用 DSL 简化创建 Rack app 的代码, Rack::Builder

通常的 Rack app 都是由多个 Rack middleware 嵌套而成的,使用 pure ruby 的写法就是:

app = MyRackApp.new
app = Rack::Lint.new(app)
app = Rack::ShowStatus.new(app)
app = Rack::ShowExceptions.new(app)
app = Rack::CommonLogger.new(app)
Rack::Handler::Thin.run app, :Port => 8080

Rack 提供了创建 Rack app 的 DSL

app = Rack::Builder.new do
  use Rack::CommonLogger
  use Rack::ShowExceptions
  use Rack::ShowStatus
  use Rack::Lint
  run MyRackApp.new
end
Rack::Handler::Thin.run app, :Port => 8080

它们的调用顺序是相反

refrence:

© 著作权归作者所有

邪云子
粉丝 18
博文 120
码字总数 24684
作品 0
朝阳
程序员
私信 提问
cloud controller 源码分析(包括Ruby on Rails项目结构分析)

本文记叙我作为一个完全不懂ror(ruby on rails)的开发者,了解ror以及cc所需的知识。全文包括了cloud controller的代码结构,MVC架构分析,最后有一个例子帮助分析。 目录结构 cc是一个ror...

长平狐
2012/08/24
475
1
理解 Rack 应用及其中间件

大多数 web 开发者都是基于高度抽象出来的接口基础上编码,很多时候我们知其然但不知其所以然,特别是使用 Rails 框架开发时。 你是否研究过 Rails 内部对请求/响应周期是如何运作的?近期我...

Yashin
2015/11/03
5K
4
Rack 中间件--better_errors

Better Errors 取代了标准的 Rails 错误提示页面,提供了更有用的错误提示页面。作为 Rack 中间件,它可以在任何 Rack 应用程序的 Rails 外使用。 特性 完整的堆栈跟踪 检查所有堆栈帧(强调...

匿名
2016/01/11
396
0
Rack:处理HTTP请求更简单

Rack提供了 Web服务器和Ruby开发框架之间的接口。它将框架编写者从为每个Web服务器单独编写一个处理模块的繁重负担中解脱出来,可以节省大量重复劳动。 Rack相当易用,如下示例便可以让你创建...

红薯
2008/11/21
1K
0
rails s 启动过程

1) 命令 rails s windows) 这里会执行 RUBY_PATH/bin/rails.bat 文件 之后将执行权交给 'RUBY_PATH/bin/rails' linux) 这里会执行 'RUBY_PATH/bin/rails' 跳转) 在 RUBY_PATH/bin/rails 中 ......

路边
2014/08/29
1K
1

没有更多内容

加载失败,请刷新页面

加载更多

二、Docker

1、Docker - The TLDR(Too Long,Don't Read,Linxu 终端工具 ) Docker是在Linux和Windows上运行的软件。它创建、管理和编排容器。该软件以开源方式开发,在Github上作为Moby开源项目的一部分。...

倪伟伟
24分钟前
2
0
Python猫荐书系列之七:Python入门书籍有哪些?

本文原创并首发于公众号【Python猫】,未经授权,请勿转载。 原文地址:https://mp.weixin.qq.com/s/ArN-6mLPzPT8Zoq0Na_tsg 最近,猫哥的 Python 技术学习群里进来了几位比较特殊的同学:一...

豌豆花下猫
今天
5
0
Guava RateLimiter限流源码解析和实例应用

在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流 缓存 缓存的目的是提升系统访问速度和增大系统处理容量 降级 降级是当服务出现问题或者影响到核心流程时,需要暂时屏蔽掉,待高...

算法之名
今天
13
0
国产达梦数据库与MySQL的区别

背景 由于项目上的需要,把项目实现国产化,把底层的MySQL数据库替换为国产的达梦数据库,花了一周的时间研究了国产的数据库-达梦数据库,它和MySQL有一定的区别,SQL的写法也有一些区别。 ...

TSMYK
今天
2
0
老也有错?35岁程序员是一道坎,横亘在每个技术职场人的心中

随着互联网的高速发展变革,大龄恐惧症越来越多地在技术圈被人讨论。很多程序员在工作5-10年以后,都会开始思考5年、10年甚至更久以后的自己,会是怎样一种生活工作状态,以及是否会被时代抛...

我最喜欢三大框架
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部