本文翻译自:Rails from Request to Response 系列;个人选择了自己感兴趣的部分进行翻译,需要阅读原文的同学请戳前面的链接。

第二部分 路由(Routing)

Blog::Application.routes 的定义也在 engine.rb 文件中:

# rails/railties/lib/rails/engine.rb

def routes
@routes ||= ActionDispatch::Routing::RouteSet.new
@routes.append(&Proc.new) if block_given?
@routes
end

Blog::Application.routes 会返回一个 ActionDispatch::Routing::RouteSet 的实例。这是我们第一次接触到 ActionDispatch 模块(module),它是 ActionPack 的一部分。

ActionDispatch :

负责处理例如「路由(Routing)」,「参数解析(Parameter Parsing)」,「Cookies」和「Sessions」之类的工作;

ActionPack :

Rails 源码的顶层的 gem 之一,功能包括:路由功能, controller (ActionController)的定义和 view (ActionView)的渲染;

RouteSet :

此类是一个Route的集合,包括一个 route 的数组(Mapper),和一个 named route (NamedRouteCollection: name 对应着一组普通的 route 集合的Hash)。负责解释和分派请求(Request)到对应的控制器(Controller)动作(Action)。

现在继续来看 engine ,回到 RouteSet 的 #call 方法,相关的代码在 actionpack/lib/action_dispatch/routing/route_set.rb 中:

# rails/actionpack/lib/action_dispatch/routing/route_set.rb

module ActionDispatch
module Routing
class RouteSet def call(env)
@router.call(env)
end ... end
end
end

RouteSet 不会处理 @router 里的事情。如果我们看一下 RouteSet constructor,会发现 @router 其实是 Journey::Router 的一个实例。

Journey

Journey 是 ActionDispatch 的核心路由模块。它的代码是非常有趣的,其中用到了广义状态转移图(generalized transition graph)和非确定性有限状态自动机(non-deterministic finite automata)来配对URLs和路由。

有兴趣的话可以拿出你的计算机科学与技术本科的教科书(译注:指的应是《形式语言与自动机》)复习一下!Journey 甚至还包含了一个完整的 yacc 语法文件来对 routes 进行语法分析。

Journey::Router 的 #call 方法有些长,下面是相关部分:

# rails/actionpack/lib/action_dispatch/journey/router.rb

module ActionDispatch
module Journey
class Router def call(env)
find_routes(env).each do |match, parameters, route|
env[@params_key] = (set_params || {}).merge parameters
status, headers, body = route.app.call(env)
return [status, headers, body]
end
end ... end
end
end

我们看到了和 Unicorn 中 #process_client 一样的 Rack 接口。 #find_routes 通过路由表 GTG (generalized transition graph) simulator 对URL进行执行。路由表本身是由 config/routes.rb 中规定的路由信息,构造的一个 Journey::Routes 实例,它包含了全部的路由(多个 Journey::Route 实例),个人十分推荐通过 RailsCasts #231#232来学习路由结构的更多细节。

倘若发现了匹配的路由,我们便调用与 route 相关联的 app 上的 #call 方法。只要我们现在在 Rails 源码中看到引用 app 的地方,就可以假定它是 Rack app 。其实每个 controller 中 action 的行为都和一个 Rack app 一样。与 route 相关联的 app 的初始化过程有一些 Tricky。

在构造路由表时, ActionDispatch::Routing::Mapper 类调用 add_route ,它将会构造 Journey::Route 的一个实例,与 controller endpoint —— the Rack app 相关联。

然而,在 mapper.rb 中这个类的定义有将近 2,000 行,以下是删减版的 Mapper#add_route 定义:

# rails/actionpack/lib/action_dispatch/routing/mapper.rb

module ActionDispatch
module Routing
class Mapper def add_route(action, options)
path = path_for_action(action, options.delete(:path)) ... mapping = Mapping.new(@set, @scope, URI.parser.escape(path), options)
app, conditions, requirements, defaults, as, anchor = mapping.to_route
@set.add_route(app, conditions, requirements, defaults, as, anchor)
end ... end
end
end

在这里, @set 是我们之前提到的 RouteSet ,这里的 app 其实是 ActionDispatch::Routing::Dispatcher 的一个实例。 Dispatcher 类定义在 route_set.rb 中,这是 #call 的一个简单定义。

为了说的更清楚,想象一下我们正在通过URL /posts 访问我们的博客应用,它的路由指向了 Posts Controller 的 index 方法。

# rails/actionpack/lib/action_dispatch/routing/route_set.rb

module ActionDispatch
module Routing
class Dispatcher def call(env)
params = env[PARAMETERS_KEY]
prepare_params!(params)
# params = {:action=>"index", :controller=>"posts"} controller = controller(params, @defaults.key?(:controller))
# controller = PostsController dispatch(controller, params[:action], env)
end ... end
end
end

在这里, controller 方法已经解析了控制器参数(比如 posts ),并且给了我们一个类(PostsController)的引用,得到了基本的参数哈希(params hash)。

现在,已经准备好了去调用控制器(controller)上的方法(aciton),来得到完整的响应(response)。以下是 dispatch 方法的定义:

# rails/actionpack/lib/action_dispatch/routing/route_set.rb

def dispatch(controller, action, env)
controller.action(action).call(env)
end

到这里,我们成功地将 route 映射到了一个 controller/action ,作为下一个 post 处理的请求(request)被压入ActionController工作栈。

路由是 Rails 中一个相当复杂的一个部分,他的方法链很长。像之前所说的,我们并没有必要了解它的全部细节。Rails 具有魔力的地方就是它为你隐藏了所有这些细节。当然去探索这整个执行过程到底是如何发生的是一件很有趣的事情。

译者总结:

实际上每个存在的 Controller 和 Action 的组合都是一个 Rack App ,假设它们存在于一个集合 rack_app_set 中;同时假设所有系统可接受的合法URL的集合为 URL_set 。

则路由为函数:

ƒ: URL_setrack_app_set

[Rails] 从 Request 到 Response(2)的更多相关文章

  1. [Rails] 从 Request 到 Response(1)

    本文翻译自:Rails from Request to Response 系列:个人选择了自己感兴趣的部分进行翻译,需要阅读原文的同学请戳前面的链接. 第一部分 导言(Introduction) 服务 ...

  2. Request 和 Response 原理

    * Request 和 Response 原理:     * request对象和response对象由服务器创建,我们只需要在service方法中使用这两个对象即可        * 继承体系结构: ...

  3. Request 、Response 与Server的使用

    纯属记录总结,以下图片都是来自 ASP.NET笔记之 Request .Response 与Server的使用 Request Response Server 关于Server.MapPath 方法看 ...

  4. request 和response

    当今web程序的开发技术真是百家争鸣,ASP.NET, PHP, JSP,Perl, AJAX 等等. 无论Web技术在未来如何发展,理解Web程序之间通信的基本协议相当重要, 因为它让我们理解了We ...

  5. Request和Response对象

    Request 和 Response 对象起到了服务器与客户机之间的信息传递作用.Request 对象用于接收客户端浏览器提交的数据,而 Response 对象的功能则是将服务器端的数据发送到客户端浏 ...

  6. Java 中的 request 和response 理解

    request和response(请求和响应)  1.当Web容器收到客户端的发送过来http请求,会针对每一次请求,分别创建一个用于代表此次请求的HttpServletRequest对象(reque ...

  7. 【转】request和response的页面跳转传参

    下面是一位园友的文章: jsp或Servlet都会用到页面跳转,可以用 request.getRequestDispatcher("p3.jsp").forward(request ...

  8. LoadRunner中取Request、Response

    LoadRunner中取Request.Response LoadRunner两个“内置变量”: 1.REQUEST,用于提取完整的请求头信息. 2.RESPONSE,用于提取完整的响应头信息. 响应 ...

  9. Spring mvc中使用request和response

    @ResponseBody @RequestMapping(value="/ip", method=RequestMethod.GET) public String getIP(H ...

随机推荐

  1. 给你的git仓库瘦身

    很久没有写博客了,最近遇到了一个git问题,比较典型,记录下来与大家分享. 我们使用git版本控制的时候享受了很多便利,不管是代码合并,分支提供给我们的并发,但我们也往往忽略了每次提交之后在我们本地项 ...

  2. 基于TcpListener实现最简单的http服务器

    最近实现一套简单的网络程序.为了查看程序内部的变量,方便调试.就在想搞一个最最简单的方式.第一个想到写文件,日志.这个不实时,而且打开麻烦,pass .于是想到用网络输出.本来是想写成c/s模式,想着 ...

  3. 基于session 的springMvc 国际化

    项目中采用springMvc的框架,需要动态切换语言,找了一些资料,最后决定采用基于session的动态切换,实现动态切换中文,英文,韩文,其实就是把中文翻译成其他语言显示 springMvc国际化包 ...

  4. 年末整理git和svn的使用心得

    实习加毕业工作也一年多了,用过svn 也用过git,现在也是两种版本管理工具交替不同的项目再用. 趁年末放假之际,来梳理下. 对于SVN常用命令: .svn cp svn-trunk地址 svn-br ...

  5. Linux中top和free命令详解(转)

    top:命令提供了实时的对系统处理器的状态监视.它将显示系统中CPU最"敏感"的任务列表. 该命令可以按CPU使用.内存使用和执行时间对任务进行排序: 而且该命令的很多特性都可以通 ...

  6. Matlab最新的官方文档中文翻译

    文章翻译的是Matlab最新的官方文档R2016b,可能后续如果我还有时间会继续翻译,希望能够帮到大家,翻译的不好请大家不要吐槽. Matlab官方文档地址:http://cn.mathworks.c ...

  7. 词典 (noi OpenJudge)

    传送门:1806:词典 神奇的STL #include <iostream> #include <cstdio> #include <cstring> #inclu ...

  8. Web框架——Django笔记

    Web框架--Django笔记 MVC和MTV MVC:Model.View.Controller MTV:Model.Template.View Django--MTV 1.创建Django程序   ...

  9. php 语言特点

    PS:绝大多数用php的企业/ 项目 活不到雇佣得起月薪35k以上的php程序员那一天,也是php码农在10年经验的时候普遍不如java程序员的原因之一. PS2: 由于薪资提升太快,很多php码农跳 ...

  10. unity3d和php后台简单交互--二

    上次我们讨论了u3d和php的简单交互,现在我们接着讨论u3d和php交互,这里我们讨论的是php的后台大家可以延伸为其他语言.在实现的开发中我们很少通过发送字符或者字段到服务器上的,我们一般会请求包 ...