<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為編寫Web應用以及Web框架提供了很多便利的工具,那么這一節,我們實現一個最簡單的Web框架。
     
    一、Web框架應該具備什么功能
    • 對request和response的存取
    • 路由:根據不同URL執行不同程序
    • 能夠處理cookies
    • 能夠存取session
    • 能夠生成日志
    • ......
     
    看上去挺麻煩的,是吧?其實,則不然
    前面我們已經知道Rack::Request和Rack::Response這兩個類可以用來處理request和 response,那么我們該如何實現路由呢?Rack提供Rack::URLMap類來處理路由,我們這里可以不直接使用這個類,如果大家仔細看Rack::Builder的實現,大家會發現這個類提供了一個map方法以及generate_map方法:
    map
    def map(path, &block) 
      @map ||= {} 
      @map[path] = block
    end
    generate_map
    def generate_map(default_app, mapping)
      mapped = default_app ? {'/' => default_app} : {}
      mapping.each { |r,b| 
        mapped[r] = self.class.new(default_app, &b).to_app 
      } 
      URLMap.new(mapped)
    end
    路由的作用其實就是根據URL請求的路徑去調用對應的程序,因此map方法它接受路徑path和 對應的程序&block,然后用hash保存其對應關系generate_map這個方法是在to_app中調用的,它主要通過URLMap建立起路由和所執行應用程序的關系。
    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方法是為了組合中間件以及應用程序的,通過這段代碼我們可以看出來, 在組合中間件之前需要先根據路由找到真正的run,然后再組裝對應的中間件。
     
    二、一個簡單的Web框架
    下面是一個簡單的web框架,具備對request、response的處理并且具有路由、日志功能。
    require 'rack'
    app = Rack::Builder.new { 
      use Rack::ContentLength 
      map '/hello' do
        use Rack::CommonLogger 
        map '/user1' do
          run lambda {|env| 
            [200, {"Content-type" => "text/html"}, ["from user1", "SCRIPT_NAME=#{env["SCRIPT_NAME"]}", "PATH_INFO=#{env["PATH_INFO"]}"]]
          }
        end
    
        map '/everyone' do
          run lambda {|env| [200, {"Content-type" => "text/html"},
    ["from everyone", "SCRIPT_NAME=#{env["SCRIPT_NAME"]}", "PATH_INFO=#{env["PATH_INFO"]}"]]
          }
        end
    
        map '/' do
          run lambda {|env| [200, {"Content-type" => "text/html"},
    ["from hello catch all", "SCRIPT_NAME=#{env["SCRIPT_NAME"]}", "PATH_INFO=#{env["PATH_INFO"]}"]]
          }
        end 
      end
    
      map '/' do
        run lambda {|env| [200, {"Content-type" => "text/html"}, ["root"]]
        }
      end
    }.to_app
    Rack::Handler::WEBrick.run app, :Port => 3000
    通過上面代碼可以看出來:
    • map是可以嵌套的
    • 可以對不同的路由使用不同的中間件組合

     

    三、rackup

    前面我們的代碼中最后一行總是這樣寫的:

    Rack::Handler::WEBrick.run xxx, :Port => 3000

    這樣做寫死了所要用的服務器,不靈活。

    Rack提供了rackup命令,允許我們用一個配置文件去執行我們的應用程序,rackup使用很簡單,我們只需要提供一個后綴為.ru的配置文件即可,然后運行 rackup xxx.ru就ok了,我們把 前面代碼改為:

    map '/hello' do 
      map '/user1' do
        run lambda {|env| [200, {"Content-type" => "text/html"}, ["from user1",
    "SCRIPT_NAME=#{env["SCRIPT_NAME"]}", "PATH_INFO=#{env["PATH_INFO"]}"]]
        }
      end
    
      map '/everyone' do
        run lambda {|env| [200, {"Content-type" => "text/html"},
    ["from everyone", "SCRIPT_NAME=#{env["SCRIPT_NAME"]}", "PATH_INFO=#{env["PATH_INFO"]}"]]
        }
      end
    
      map '/' do
        run lambda {|env| [200, {"Content-type" => "text/html"},
    ["from hello catch all", "SCRIPT_NAME=#{env["SCRIPT_NAME"]}", "PATH_INFO=#{env["PATH_INFO"]}"]]
        }
      end 
    end
    
    map '/' do
      run lambda {|env| [200, {"Content-type" => "text/html"}, ["root"]]
      }
    end
    保存上述代碼到config.ru文件然后運行 rackup config.ru即可。
    posted @ 2022-05-12 00:24  阿拉懶神燈  閱讀(5)  評論(0編輯  收藏  舉報
    国产美女a做受大片观看