zoukankan      html  css  js  c++  java
  • How rackup works

      “rack是一个最简化的web application标准”,这句话在很多资料里面见到过很多次,并且都会给出一个5行代码的例子,然后一个web application华丽丽的就起来了。确实比较简单,看看这个一页纸的specification就知道了。但是看了很多次之后还是没有什么感觉,一个简单的specification当然不能帮助你启动程序,需要的是它的实现,而且rack只是application的标准,还需要第三方的web server作为支持。还好rack这个gem帮我们实现了这个specification和相关的一些功能,并且打包了常用的web server,比如webrick和thin。最后还提供了一个命令行工具:rackup。

      看一个rack gem里面提供的rackup的例子:

    // lobster.ru

    require 'rack/lobster'
    
    use Rack::ShowExceptions
    run Rack::Lobster.new

      然后调用rackup lobster.ru就可以了。其中使用到了use和run这样的DSL,那么这些DSL是怎么实现的,rackup的过程是如何发生的呢,且看我慢慢道来吧。

      先看看rackup这个可执行文件:

    // rackup

    1 #!/usr/bin/env ruby
    2 
    3 require "rack"
    4 Rack::Server.start

      恩~没什么特别的,看看Rack::Server里面做了什么

    // server.rb

     1 require 'optparse'
     2 
     3 module Rack
     4   class Server
     5     ...
     6     def self.start(options = nil)
     7       new(options).start
     8     end
     9     ...
    10   end
    11 end

      OK,又代理到了实例方法start

    1 def start &blk
    2   #一些parse参数的代码
    3   wrapped_app
    4 
    5   daemonize_app if options[:daemonize]
    6   ...
    7 
    8   server.run wrapped_app, options, &blk
    9 end

      恩~,这里的warped_app是用来生成我们的rack app的核心代码

    1 def wrapped_app
    2     @wrapped_app ||= build_app app
    3 end

      又引出了build_app和app这两个函数,先看app

     1 def app
     2   @app ||= begin
     3     if !::File.exist? options[:config]
     4       abort "configuration #{options[:config]} not found"
     5     end
     6 
     7     app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
     8     self.options.merge! options
     9     app
    10   end
    11 end

      重点来了,options这个函数把命令行中传入的lobster.ru这个文件放到了options[:config]以供使用。然后再使用Rack::Builder.parse_file这个方法来解析ru配置文件。

     1 def self.parse_file(config, opts = Server::Options.new)
     2   options = {}
     3   if config =~ /\.ru$/
     4     cfgfile = ::File.read(config)
     5     #对cfgfile做点处理
     6     app = eval "Rack::Builder.new {\n" + cfgfile + "\n}.to_app",
     7       TOPLEVEL_BINDING, config
     8   else
     9     #这种情况下config文件只是定义了一个rack app的类
    10     require config
    11     app = Object.const_get(::File.basename(config, '.rb').capitalize)
    12   end
    13   return app, options
    14 end

      there you go,第6行使用了eval来把ru配置文件里面的那些代码在一个Rack::Builder的实例的上下文中执行,于是Rack::Builder中定义的方法run,use就都可用了。use是用来添加middleware,run应该是用来启动程序了吧?其实不是。。真正启动server的代码在上面列出来了,就是在Server的实例方法start的最后一行。顺便说一句,第6行的那个to_app还提供了url mapping的功能,不过还没仔细看。

      后面的代码就不再赘述了。大概说下,就是在构造好了rack app上添加middleware,然后使用default的web server来运行它。

      最后给个链接,里面给出了很多rack相关的链接,很是不错:http://jasonseifer.com/2009/04/08/32-rack-resources-to-get-you-started

  • 相关阅读:
    开通博客第一天
    Vue 打包配置productionSourceMap 的记录
    supervisorctl 的 简单记录
    mvn打包方式记录
    springboot日志配置,关于logback
    springboot集成swagger
    关于mapper文件的bean
    elasticsearch 连接、操作记录
    关于前后端分离文件上传的些许问题
    代码优化--策略模式的四种表现
  • 原文地址:https://www.cnblogs.com/cuiliqiang/p/2499937.html
Copyright © 2011-2022 走看看