`
andyhu1007
  • 浏览: 199274 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Rails每周一题(二十): Rack变革

阅读更多

 

    Rack,貌似已经把Rails改革了。

Rack

    Rack是什么?Rack提供了用ruby开发web应用的一个接口。比如Rails框架,就是由rack承担着跟web服务器之间的交互。简而言之,Rack已经成为ruby开发web应用程序的一个规范,它统一了web服务器和web框架之间的交互接口。它所支持的web服务器和web框架已经非常之多:http://rack.rubyforge.org/doc/ 。 

 

    Rack的规范非常简单,就是一个call方法:http://rack.rubyforge.org/doc/SPEC.html 。接受一个environment,然后返回status,header和body。这不就是http的全部么?

 

Rack Middleware

    为什么不可以在Rack和web framework之间做些事情呢?于是Rack middleware发展起来了。Rack中间件其实就是一些遵循Rack规范的应用。为什么要发展出Rack middleware?因为很多事情在这里做起来就非常方便,其实就是AOP的方式(你也可以把它理解成filter)。

 

     看一下众多的middlewares:http://wiki.github.com/rack/rack/list-of-middleware 。或者在你的最新(2.3)rails应用下敲下命令行:rake middleware。

 

     ParamsParser:

 

 

def call(env)
  if params = parse_formatted_parameters(env)
    env["action_controller.request.request_parameters"] = params
  end

  @app.call(env)
end

 

    CookieStore:

 

 

      def call(env)
        env[ENV_SESSION_KEY] = AbstractStore::SessionHash.new(self, env)
        env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup

        status, headers, body = @app.call(env)

        session_data = env[ENV_SESSION_KEY]
        options = env[ENV_SESSION_OPTIONS_KEY]

        if !session_data.is_a?(AbstractStore::SessionHash) || session_data.send(:loaded?) || options[:expire_after]
          session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?)
          session_data = marshal(session_data.to_hash)

          raise CookieOverflow if session_data.size > MAX

          cookie = Hash.new
          cookie[:value] = session_data
          unless options[:expire_after].nil?
            cookie[:expires] = Time.now + options[:expire_after]
          end

          cookie = build_cookie(@key, cookie.merge(options))
          unless headers[HTTP_SET_COOKIE].blank?
            headers[HTTP_SET_COOKIE] << "\n#{cookie}"
          else
            headers[HTTP_SET_COOKIE] = cookie
          end
        end

        [status, headers, body]
      end

 

    Middleware,正不就是做这些事情的好地方么?

 

    又比如,某人开发的google_analytic middleware:

 

 

    def call env
      status, headers, response = app.call(env)
 
      if headers["Content-Type"] =~ /text\/html|application\/xhtml\+xml/
        body = ""
        response.each { |part| body << part }
        index = body.rindex("</body>")
        if index
          body.insert(index, tracking_code(options[:web_property_id]))
          headers["Content-Length"] = body.length.to_s
          response = [body]
        end
      end
 
      [status, headers, response]
    end
 

Rails on Rack

    请再次用rake middleware看看清楚。

 

use Rack::Lock
use ActionController::Failsafe
use ActionController::Session::CookieStore, #<Proc:0x01a76984@(eval):8>
use Rails::Rack::Metal
use ActionController::ParamsParser
use Rack::MethodOverride
use Rack::Head
use ActionController::StringCoercion
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
run ActionController::Dispatcher.new
 

 

    没错,在Rails2.3之后,所有的东西都变成middleware了,包括Action Controller stack本身。

 

    Rails应用的调用就是对middleware堆栈的调用。从最初始的Rack::Lock:

 

def call(env)
  old, env[FLAG] = env[FLAG], false
  @lock.synchronize { @app.call(env) }
ensure
  env[FLAG] = old
end
 

    到最后的ActionController::Dispacher.new:

 

 

    def call(env)
      if @@cache_classes
        @app.call(env)
      else
        Reloader.run do
          # When class reloading is turned on, we will want to rebuild the
          # middleware stack every time we process a request. If we don't
          # rebuild the middleware stack, then the stack may contain references
          # to old classes metal classes, which will b0rk class reloading.
          build_middleware_stack
          @app.call(env)
        end
      end
    end
 

    而dispacher,正是Action Controller stack开始启动的地方。上面代码中的@app本身,也是一个middleware:

 

 

     def build_middleware_stack
        @app = @@middleware.build(lambda { |env| self.dup._call(env) })
      end

 

    _call(env)到底做了什么,还是看个究竟吧:

 

 

   def _call(env)
      @env = env
      dispatch
    end

    def dispatch
      begin
        run_callbacks :before_dispatch
        Routing::Routes.call(@env)
      rescue Exception => exception
        if controller ||= (::ApplicationController rescue Base)
          controller.call_with_exception(@env, exception).to_a
        else
          raise exception
        end
      ensure
        run_callbacks :after_dispatch, :enumerator => :reverse_each
      end
    end

 

   你没发现,大部分主要对象都实现了call(env)接口么?

Rails Metal Applications

    Rails2.3集成进了Metal Application,它的作用主要是应付那些“少而多”的request。这里的少,是指访问数据库少,逻辑少(个人认为逻辑复杂的不适合放在metal里面做),多是指访问次数多(如果访问频率没有那么高,我觉得没必要)。当数据库访问非常之少时,性能的瓶颈已经在Action Controller stack,问题就来了:为什么不绕开Action Controller stack呢?Metal的作用就是这样的,它作为Rack middleware stack的一分子(在上面那个list中找),在到达Action Controller stack之前对request进行拦截,如果满足,则直接返回。还是看下源代码吧:

 

      def call(env)
        @metals.keys.each do |app|
          result = app.call(env)
          return result unless @pass_through_on.include?(result[0].to_i)
        end
        @app.call(env)
      end

 

    http://github.com/rails/rails/blob/master/railties/lib/rails/rack/metal.rb

 

 

更多

     关于更多的知识,请见:http://guides.rubyonrails.org/rails_on_rack.html 。在这里会看到script/server的实现,如何定制rackup,如何定制middleware,如何生成metal等。

 

EOF

 

  ps:

 

  技术总是翻天覆地地变化着,rails2.3又有了很多不同。做一个IT民工还真是他妈的累,不过如果可以苦中作乐,倒也认了。每周一题 越来越名不副实了,不过还是继续学习,继续写吧。

分享到:
评论
7 楼 dazuiba 2009-12-03  
鼓励鼓励!

Rack的middleware用起来真别扭。  我敢打赌这绝对不是Rails Core team设计的。

提供的call stack和Method Chain很难理解, 也很难用。
6 楼 samsam 2009-12-01  
讲的非常赞,学习了
5 楼 andyhu1007 2009-12-01  
zy8643954 写道
这个页面上的前面两个不是javaeye内部的链接,点击了之后既然提示要登录。貌似我已经登录了。


不好意思,修改了。javaeye的编辑功能做得太差了。这么多bug,也不见修正。
4 楼 zy8643954 2009-12-01  
这个页面上的前面两个不是javaeye内部的链接,点击了之后既然提示要登录。貌似我已经登录了。
3 楼 axgle 2009-12-01  
没有java语法之表,而有java抽象之实。所以这不是技术,就像oop一样,是哲学吧.
2 楼 flyerhzm 2009-11-30  
mycybyb 写道
那我是不是可以把它看成java中的servlet呢


看成servlet filter更贴切
1 楼 mycybyb 2009-11-30  
那我是不是可以把它看成java中的servlet呢

相关推荐

    Rails的精简版本Rails::API.zip

    Rails::API 是 Rails 的精简版本,针对不需要使用完整 Rails 功能的开发者。 Rails::API 移除了 ActionView 和其他一些渲染功能,不关心Web前端的开发者可更容易、快速地开发应用程序,因此运行速度比正常的 Rails ...

    Rails上的API:使用Rails构建REST APIAPIs on Rails: Building REST APIs with Rails

    在本篇内容中,我们将深入探讨如何利用Ruby on Rails(简称Rails)这一强大的Web应用程序框架来构建可伸缩且易于维护的RESTful API。Rails以其简洁优雅的语法、高效的开发速度以及良好的社区支持而闻名,这使得它...

    Rails中应用Ext.tree:以中国的省市地区三级联动选择为例

    这篇博客文章“Rails中应用Ext.tree:以中国的省市地区三级联动选择为例”提供了一个实用的示例,教我们如何利用Ext.js库中的Tree组件来实现这种功能。 首先,让我们了解Rails和Ext.js的基本概念。Rails是基于Ruby...

    ROR绿色最新环境(2013/3/10)

    Rails::Rack::Logger ActionDispatch::ShowExceptions ActionDispatch::DebugExceptions ActionDispatch::RemoteIp ActionDispatch::Reloader ActionDispatch::Callbacks ActiveRecord::ConnectionAdapters::...

    Ruby-RailsFootnotes在每一个Rails页脚展示应用程序的相关信息方便调试

    config.middleware.use Rails::Rack::Debugger config.middleware.use RailsFootnotes ``` 4. 重启Rails服务器以使更改生效。 5. 访问任何Rails应用页面,你将在页脚看到Footnotes链接,点击它们即可查看相关...

    Rack::UTF8Sanitizer.zip

    Rack::UTF8Sanitizer 是一个 Rack 中间件用来清理 URI 和 HTTP 请求头部中包含的无效 UTF-8 字符。Rails 的使用方法:config.middleware.insert 0, Rack::UTF8SanitizerRack 的使用方法:use Rack::UTF8Sanitizer

    Rails相关电子书汇总二

    标题 "Rails相关电子书汇总二" 提供的信息表明,这个压缩包包含的资源主要与Ruby on Rails框架有关,特别是从“Rubyisms in Rails”的书名来看,我们可以期待它深入探讨了Ruby语言在Rails框架中的独特用法和特性。...

    Ruby On Rails 面试系列七,一个面试练习题

    这个面试练习题可能是为了测试应聘者对于Rails应用的构建、自动化任务管理、测试驱动开发(TDD)以及文件组织结构的理解。让我们逐一探讨这些知识点。 首先,`Rakefile`是Ruby中的构建工具,类似于其他语言的...

    Rails 101 入门电子书

    - 安装Rails: 使用gem工具安装最新的Rails版本。 - 测试安装: 创建一个简单的Rails应用来验证是否成功安装。 #### 五、练习作业0-Hello World - **目标**: - 学习如何创建第一个Rails应用程序。 - **过程**: -...

    Ruby on Rails入门例子

    Ruby on Rails,简称Rails,是一种基于Ruby语言的开源Web应用程序框架,它遵循MVC(Model-View-Controller)架构模式,旨在使Web开发过程更加高效、简洁。本篇将通过一个入门实例,深入探讨Rails的基本概念和核心...

    Advanced Rails

    Rails,全称为Ruby on Rails,是一款基于Ruby编程语言的开源Web应用程序框架,以其MVC(模型-视图-控制器)架构模式而闻名。"Advanced Rails" 涵盖了Rails开发中的高级主题和技术,是Ruby on Rails学习进阶的重要...

    wdi_3_rack_rails_lite:使用 Rack 创建 Rails 精简版

    我们将从 Ruby、Rack 和 ActiveSupport 构建一个应用程序。 本课的目的是从内部展示 Rails 是如何工作的。 这将逐步构建一些 Rails 组件的精简版。 它会: 创建一个类似Rails 的初始化过程。 使用 Rails 目录...

    Rails相关电子书汇总

    Ruby on Rails,通常简称为Rails,是一个基于Ruby语言的开源Web应用程序框架,它遵循MVC(模型-视图-控制器)架构模式,以简洁、高效的代码和“约定优于配置”的理念著称。此压缩包中的"rubyonrails21-cn.pdf"可能是...

    Ruby+on+Rails快速Web应用开发实战.pdf

    Ruby on Rails(简称RoR或Rails)是一种开源的网络应用框架,用Ruby语言编写。它被设计用来轻松地实现MVC(模型-视图-控制器)设计模式,从而使开发人员能够快速和有条理地创建数据驱动的应用程序。接下来,我将详细...

    rails5-docker-alpine:使用Alpine Linux的Rails轻量级Docker开发环境

    rails5-docker-alpine:使用Alpine Linux的Rails轻量级Docker开发环境

    rails-auth:RailsRack的基于资源的模块化身份验证和授权

    Rails :: Auth是一个灵活的库,旨在使用Rack Middleware进行身份验证(AuthN)和授权(AuthZ)。 它将,使用AuthN中间件首先验证凭据(例如X.509证书或cookie),然后通过使用这些凭据(例如(ACL))的单独AuthZ...

    mailgun_webhooks:Mailgun Webhooks 的 Rails 和 Rack 集成

    Mailgun 网络钩子 为您的 Rack 或 Rails 应用程序添加对 Mailgun webhook... 只需将MailgunWebhooks::Rack添加到您的中间件堆栈中即可。 use MailgunWebhooks :: Rack网络钩子默认情况下,您的应用程序将侦听/mailgun上

    chef-rails, 厨房设置一个可以与 Nginx 和 Rails 一起滚动的Ubuntu服务器.zip

    chef-rails, 厨房设置一个可以与 Nginx 和 Rails 一起滚动的Ubuntu服务器 主厨 rails安装一个准备为 Ruby on Rails 栈准备的Ubuntu服务器:NginxPostgreSQLRedisMemcached带RVM的rubyPhusion乘客独立要求Ubuntu ...

    Ruby on Rails Guides v2 - Ruby on Rails 4.2.5

    ### Ruby on Rails Guides v2 - Ruby on Rails 4.2.5 #### 一、重要概念及基础假设 - **重要概念**:本指南旨在帮助读者深入理解Ruby on Rails(以下简称Rails)4.2.5版本的核心功能与最佳实践。 - **基础假设**:...

Global site tag (gtag.js) - Google Analytics