`
jlaky
  • 浏览: 42065 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Rails请求的生命周期

阅读更多

之前在csdn写了不少关于Rails的笔记,不过觉得一个文件一个文件来读不够有条理,现在可以从更加实用和课题式的角度来读Rails代码。

 

以WEBrick为例子,WEBrick的请求处理代码如下:

 

  def service(req, res) #:nodoc:
    unless handle_file(req, res) # 如果不是处理文件请求
      begin
        REQUEST_MUTEX.lock unless ActionController::Base.allow_concurrency
        unless handle_dispatch(req, res)
          raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found."
        end
      ensure
        unless ActionController::Base.allow_concurrency
          REQUEST_MUTEX.unlock if REQUEST_MUTEX.locked?
        end
      end
    end
  end

 

处理html请求,进入handle_dispatch方法

 

  def handle_dispatch(req, res, origin = nil) #:nodoc:
    data = StringIO.new
    Dispatcher.dispatch(
      CGI.new("query", create_env_table(req, origin), StringIO.new(req.body || "")), 
      ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, 
      data
    )
    
    header, body = extract_header_and_body(data) #从返回的data中获取相应header和body

    set_charset(header)
    assign_status(res, header)
    res.cookies.concat(header.delete('set-cookie') || [])
    header.each { |key, val| res[key] = val.join(", ") }
    
    res.body = body
    return true
  rescue => err
    p err, err.backtrace
    return false
  end

 

    def extract_header_and_body(data)
      data.rewind
      data = data.read

      raw_header, body = *data.split(/^[\xd\xa]{2}/on, 2)
      header = WEBrick::HTTPUtils::parse_header(raw_header)
      
      return header, body
    end
 

 

ActionController::Dispatcher里的调用过程如下:

 

      def dispatch(cgi = nil, session_options = CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout)
        new(output).dispatch_cgi(cgi, session_options)
      end

    def dispatch_cgi(cgi, session_options)
      if cgi ||= self.class.failsafe_response(@output, '400 Bad Request') { CGI.new } #确保能生成response对象
        @request = CgiRequest.new(cgi, session_options)
        @response = CgiResponse.new(cgi)
        dispatch
      end
    rescue Exception => exception
      failsafe_rescue exception
    end

 

调用dispatch方法

 

这里有两个钩子方法before_dispatch和after_dispatch

    def dispatch
      @@guard.synchronize do
        begin
          run_callbacks :before_dispatch
          handle_request
        rescue Exception => exception
          failsafe_rescue exception
        ensure
          run_callbacks :after_dispatch, :enumerator => :reverse_each
        end
      end
    end 

 

处理单个请求

      def handle_request
        @controller = Routing::Routes.recognize(@request)
        @controller.process(@request, @response).out(@output)
      end

 

调用ActionController的process方法,process里面调用了一系列方法

 

      # Extracts the action_name from the request parameters and performs that action.
      def process(request, response, method = :perform_action, *arguments) #:nodoc:
        initialize_template_class(response)
        assign_shortcuts(request, response)
        initialize_current_url
        assign_names
        forget_variables_added_to_assigns

        log_processing
        send(method, *arguments)

        assign_default_content_type_and_charset

        response.request = request
        response.prepare! unless component_request?
        response
      ensure
        process_cleanup
      end
 

send(method,*arguments)就是调用当前controller对应的action方法,

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics