<input id="ohw05"></input>
  • <table id="ohw05"><menu id="ohw05"></menu></table>
  • <var id="ohw05"></var>
  • <code id="ohw05"><cite id="ohw05"></cite></code>
    <label id="ohw05"></label>
    <var id="ohw05"></var>
  • Rack相關知識梳理(二)

    一、Rack中間件

    1、什么是中間件

    中間件其實就是Ruby應用服務器和Rack應用程序之間執行的代碼

    2、一個簡單的例子

    $LOAD_PATH.unshift(File.dirname(__FILE__)) 
    require 'rack'
    require 'decorator'
    my_app = lambda { |env|
      request = Rack::Request.new(env)
      response = Rack::Response.new 
      response["Content-Type"] = "text/html"
      if request.path_info == "/hello"
        response.write("you say hello")
      else
        response.write("you need say something") 
      end
      response.finish 
    }
    
    Rack::Handler::WEBrick.run Decorator.new(my_app), :Port => 3000
    這段代碼中我們的rack應用程序是一個lambda(lambda具有call方法的) 前面幾行沒什么好說的,大家看最后一句:
    Rack::Handler::WEBrick.run Decorator.new(my_app), :Port => 3000
    我們最后傳給run的是Decorator對象,這個對象在構造時接受一個rack應用為參數,這個實例既然能被Handler調用,可想而知,我們Decorator必然具備call方法,所以我們也就清楚這個類的結構如下:
    class Decorator 
      def initialize(app) 
        ......
      end
    
      def call(env)
        ......
      end
    end
    ok,接下來我們編寫Decorator
    class Decorator 
      def initialize(app)
        @app = app
      end
    
      def call(env)
        status, headers, body = @app.call(env)
        new_body = "=======beader=========<br/>" 
        body.each { |str| new_body << str }
        new_body << "<br/>======footer=========" 
        headers["Content-Length"] = new_body.bytesize.to_s
        [status, headers, [new_body]]
      end 
    end
    啟動應用,在瀏覽器上看看效果:
    =======beader=========
    you say hello
    ======footer=========
    由上可知,Decorator運行在Ruby應用服務器和Rack應用程序之間,因此Decorator就是一個中間件,而且我們可以知道,任何Rack中間件必然是一個合法的Rack應用程序。
    3、為什么要用中間件
    中間件可以實現通用邏輯和業務邏輯分離,并且這些通用邏輯可以應用到各種各樣的業務邏輯中。

     

    二、裝配中間件

    前面我看到一個Rack中間件必然是一個合法的Rack應用程序,那么我們不難想到,一個中間件 外面可以在包裝一個中間件,每一個中間件都是獨立的,只關心自己的邏輯實現,這樣我們就 可以對整個框架或系統中的中間件進行替換,我們還可以用不同的方式去組合多個中間件,從 而滿足我們的需求。

    1、如何裝配中間件

    我們往往會在一個應用程序中使用多個中間件,最直接的辦法就是new出我們需要的中間件,

    例如我們要用middleware1和middleware2兩個中間件,那我們可以這樣編寫代碼:

    Rack::Handler::WEBrick.run middleware1.new(middleware2.new(rack_app)), :Port => 3000

    當然這并不是一個好辦法,如果我們要用的中間件非常多,那這段代碼就會非常冗?,好在Rack已經想到這一點,并且提供了一個非常好的辦法:
    Rack::Builder
    我們利用Builder修改我們之前的代碼:
    app = lambda { |env|
      request = Rack::Request.new(env) 
      response = Rack::Response.new 
      response["Content-Type"] = "text/html" 
      if request.path_info == "/hello"
        response.write("you say hello") 
      else
        response.write("you need say something") 
      end
      response.finish 
    }
    
    my_app = Rack::Builder.new { 
      use Decorator
      run app
    }.to_app
    Rack::Handler::WEBrick.run my_app, :Port => 3000
    如果要用多個中間件,那就寫成這樣:
    use middleware1
    use middleware2
    user middleware3
    ......
    PS:前面大家可能注意到,中間件采用了裝飾器的設計模式,所以當使用多個中間件時,各個中間件之間順序是需要注意的

    我們來看看Builder中幾個重要的方法

    initialize
    def initialize(default_app = nil,&block)
      @use, @map, @run, @warmup = [], nil, default_app, nil 
      instance_eval(&block) if block_given?
    end
    initialize:構造方法,能夠接受語句塊
     
    use
    def use(middleware, *args, &block) 
      if @map
        mapping, @map = @map, nil
        @use << proc { |app| generate_map app, mapping } 
      end
      @use << proc { |app| middleware.new(app, *args, &block) } 
    end
    use:記錄要創建的中間件及其順序。
     
    run
    def run(app) 
      @run = app
    end
    run:記錄原始的應用程序
     
    to_app
    def to_app
      app = @map ? generate_map(@run, @map) : @run 
      fail "missing run or map statement" unless app
      app = @use.reverse.inject(app) { |a,e| e[a] } 
      @warmup.call(app) if @warmup
      app
    end
    to_app:根據use和run中的紀錄組合最終的應用程序
     
    posted @ 2022-05-12 00:09  阿拉懶神燈  閱讀(9)  評論(0編輯  收藏  舉報
    国产美女a做受大片观看