原创作者: hideto
阅读:2100次
评论:0条
更新时间:2011-05-26
看看Rails的request/response源码吧,非常有趣,有些方法非常实用
1,request.rb:
2,response.rb:
3,cgi_process.rb:
Controller的入口方法process_cgi调用了process方法,参数为CgiRequest对象和CgiResponse对象,process处理action调用和模板render,然后返回response.out方法的返回值
CgiResponse的out方法则调用output.write(@body),即write response.body并返回给浏览器端,这就是一个Rails URL访问的完整流程
request里有很多有用的方法,request.method、request.xhr?、request.remote_ip、request.subdomains、request.session、request.cookies等都是我们常用的
1,request.rb:
module ActionController class AbstractRequest def method @request_method ||= (!parameters[:_method].blank? && @env['REQUEST_METHOD'] == 'POST') ? parameters[:_method].to_s.downcase.to_sym : @env['REQUEST_METHOD'].downcase.to_sym @request_method == :head ? :get : @request_method end def get? method == :get end def post? method == :post end def put? method == :put end def delete? method == :delete end def head? @env['REQUEST_METHOD'].downcase.to_sym = :head end def content_type @content_type ||= begin content_type = @env['CONTENT_TYPE'].to_s.downcase if x_post_format = @env['HTTP_X_POST_DATA_FORMAT'] case x_post_format.to_s.downcase when 'yaml' content_type = 'application/x-yaml' when 'xml' content_type = 'application/xml' end end Mime::Type.lookup(content_type) end end def accepts @accepts ||= if @env['HTTP_ACCEPT'].to_s.strip.empty? [ content_type, Mime::ALL ] else Mime::Type.parse(@env['HTTP_ACCEPT']) end end def xml_http_request? not /XMLHttpRequest/i.match(@env['HTTP_X_REQUESTED_WITH']).nil? end alias xhr? :xml_http_request? def remote_ip return @env['HTTP_CLIENT_IP'] if @env.include? 'HTTP_CLIENT_IP' if @env.include? 'HTTP_X_FORWARDED_FOR' then remote_ips = @env['HTTP_X_FORWARDED_FOR'].split(',').reject do |ip| ip =~ /^unknown$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i end return remote_ips.first.strip unless remote_ips.empty? end @env['REMOTE_ADDR'] end def domain(tld_length = 1) return nil if !/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/.match(host).nil? or host.nil? host.split('.').last(1 + tld_length).join('.') end def subdomains(tld_length = 1) return [] unless host parts = host.split('.') parts[0..-(tld_length+2)] end def request_uri if uri = @env['REQUEST_URI'] (%r{^\w+\://[^/]+(/.*|$)$} =~ uri) ? $1 : uri else script_filename = @env['SCRIPT_NAME'].to_s.match(%r{[^/]+$}) uri = @env['PATH_INFO'] uri = uri.sub(/#{script_filename}\//, '') unless script_filename.nil? unless (env_qs = @env['QUERY_STRING']).nil? || env_qs.empty? uri << '?' << env_qs end @env['REQUEST_URI'] = uri end end def protocol ssl? ? 'https://' : 'http://' end def ssl? @env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https' end def port @port_as_int ||= @env['SERVER_PORT'].to_i end def cookies end def session end end end
2,response.rb:
module ActionController class AbstractResponse DEFAULT_HEADERS = { "Cache-Control" => "no-cache" } attr_accessor :body, :headers, :session, :cookies, :assigns, :template, :redirected_to, :redirected_to_method_params, :layout def initialize @body, @headers, @session, @assigns = "", DEFAULT_HEADERS.merge("cookie" => []), [], [] end def content_type=(mime_type) @headers["Content-Type"] = charset ? "#{mime_type}; charset=#{charset}" : mime_type end def content_type content_type = String(@headers["Content-Type"]).split(";")[0] content_type.blank? ? nil : content_type end def charset=(encoding) @headers["Content-Type"] = "#{content_type || "text/html"}; charset=#{encoding}" end def charset charset = String(@headers["Content-Type"]).split(";")[1] charset.blank? ? nil : charset.strip.split("=")[1] end def redirect(to_url, permanently = false) @headers["Status"] = "302 Found" unless @headers["Status"] == "301 Moved Permanently" @headers["Location"] = to_url @body = "<html><body>You are being <a href=\"#{to_url}\">redirected</a>.</body></html>" end end end
3,cgi_process.rb:
module ActionController class Base def self.process_cgi(cgi = CGI.new, session_options = {}) new.process_cgi(cgi, session_options) end def process_cgi(cgi, session_options = {}) process(CgiRequest.new(cgi, session_options), CgiResponse.new(cgi)).out end end class CgiRequest < AbstractRequest attr_accessor :cgi, :session_options DEFAULT_SESSION_OPTIONS = { :database_manager => CGI::Session::PStore, :prefix => "ruby_sess.", :session_path => "/" } unless const_defined?(:DEFAULT_SESSION_OPTIONS) def initialize(cgi, session_options = {}) @cgi = cgi @session_options = session_options @env = @cgi.send(:env_table) super() end def cookies @cgi.cookies.freeze end def session unless defined?(@session) if @session_options == false @session = Hash.new else stale_session_check! do case value = session_options_with_string_keys['new_session'] when true @session = new_session when false begin @session = CGI::Session.new(@cgi, session_options_with_string_keys) rescue ArgumentError @session = Hash.new end when nil @session = CGI::Session.new(@cgi, session_options_with_string_keys) else raise ArgumentError, "Invalid new_session option: #{value}" end @session['__valid_session'] end end end @session end end class CgiResponse < AbstractResponse def initialize(cgi) @cgi = cgi super() end def out(output = $stdout) convert_content_type! set_content_length! output.binmode if output.respond_to?(:binmode) output.sync = false if output.respond_to?(:sync=) begin output.write(@cgi.header(@headers)) if @cgi.send(:env_table)['REQUEST_METHOD'] == 'HEAD' return elsif @body.respond_to?(:call) output.flush if output.respond_to?(:flush) @body.call(self, output) else output.write(@body) end output.flush if output.respond_to?(:flush) rescue Errno::EPIPE, Errno::ECONNRESET end end end end
Controller的入口方法process_cgi调用了process方法,参数为CgiRequest对象和CgiResponse对象,process处理action调用和模板render,然后返回response.out方法的返回值
CgiResponse的out方法则调用output.write(@body),即write response.body并返回给浏览器端,这就是一个Rails URL访问的完整流程
request里有很多有用的方法,request.method、request.xhr?、request.remote_ip、request.subdomains、request.session、request.cookies等都是我们常用的
评论 共 0 条 请登录后发表评论