Sinatra源码学习【下】

简介: Sinatra是一个ruby的轻量级Web框架,这这个框架总共就1000多行代码,非常简洁,值得一读。 一、Sinatra组成 Sinatra的主要实现的代码在base.rb中,主要有以下几个部分: Request:继承于Rack::Request,用于描述一个请求,通过这个类可以很方便获取到请求

三、请求处理


前面说了很多,不过都是相当于Sinatra的初始化,当我们服务端接收到请求后,Sinatra会怎 么做呢?


对于rack应用程序,当收到请求后,就会执行rack程序的call方法,前面我们看到了Base类中 就实现了call接口,我们进去看下这里面做了什么:


def call(env) 
  dup.call!(env)
end
def call!(env) 
  # :nodoc:
  @env = env
  @request = Request.new(env)
  @response = Response.new
  @params = indifferent_params(@request.params) 
  template_cache.clear if settings.reload_templates force_encoding(@params)
  @response['Content-Type'] = nil
  invoke { dispatch! }
  invoke { error_block!(response.status) } unless @env['sinatra.error']
  unless @response['Content-Type']
    if Array === body and body[0].respond_to? :content_type
      content_type body[0].content_type 
    else
       content_type :html 
    end
  end
  @response.finish 
end


我们直接看call!方法就行了,这里面一开始根据环境参数实例化request,然后实例化 response,接着获取具名参数对应的值。


@env = env
@request = Request.new(env)
@response = Response.new
@params = indifferent_params(@request.params)


前面准备工作完毕后,接下来就是真正执行我们请求的地方了


invoke { dispatch! }


我们进去看下dispatch!方法:


def dispatch! 
  invoke do
    static! if settings.static? && (request.get? || request.head?) 
    filter! :before
    route!
  end
  rescue ::Exception => boom
    invoke { handle_exception!(boom) } 
  ensure
    begin
      filter! :after unless env['sinatra.static_file']
    rescue ::Exception => boom
      invoke { handle_exception!(boom) } unless @env['sinatra.error']
    end 
end


这个方法其实就是调度请求,执行请求所对应的程序,具体实现在route!方法中:


def route!(base = settings, pass_block = nil)
  if routes = base.routes[@request.request_method]
    routes.each do |pattern, keys, conditions, block|
      returned_pass_block = process_route(pattern, keys, conditions) do |*args|
        env['sinatra.route'] = block.instance_variable_get(:@route_name)
        route_eval { block[*args] } 
      end
      # don't wipe out pass_block in superclass
      pass_block = returned_pass_block if returned_pass_block 
    end
  end
  # Run routes defined in superclass.
  if base.superclass.respond_to?(:routes)
    return route!(base.superclass, pass_block) 
  end
  route_eval(&pass_block) if pass_block
  route_missing 
end


前面我们说过,路由注册进来后呢,保存的数据结构是类似于这样的: 


{‘GET’ => [[pattern, keys, conditions, block], [pattern, keys, conditions, block]......], ‘POST’ => [......]}


所以下面这部分代码就是遍历查找匹配的路由,然后执行我们所写的那些语句块


routes.each do |pattern, keys, conditions, block|
  returned_pass_block = process_route(pattern, keys, conditions) do |*args|
    env['sinatra.route'] = block.instance_variable_get(:@route_name)
    route_eval { block[*args] } 
  end
  ......
end


大家可能注意到,正是因为他这个遍历,所以我们所写的路由他的匹配顺序是有先后的,先定义的路由若能匹配上,那就会执行先定义的路由。


route!这个方法后面他还会执行我们这个应用的父类的对应的请求的路由,为什么会这么做 呢?我的理解可能是:如果我们利用Sinatra编写模块化应用,我们可能会有多个继承 Sinatra::Base的类,我们如果将其中一个类作为代理,那么我们真正的应用应该是代理的父 类,这样的话的,Sinatra就会先执行代理中的路由然后再执行我们应用中的路由,当然我也没 有这样写过哈,这仅仅是我的一些看法,如有不同想法,欢迎随时交流。

相关文章
|
前端开发 安全 API
前端学 Ruby:前言
前端学 Ruby:前言
108 0
|
6月前
|
缓存 中间件 调度
经验大分享:Sinatra源码学习
经验大分享:Sinatra源码学习
39 0
|
开发框架 移动开发 网络协议
php进阶编程-easyswoole框架的学习和开发
php进阶编程-easyswoole框架的学习和开发
169 0
php进阶编程-easyswoole框架的学习和开发
|
存储 JavaScript 前端开发
grunt入门笔记
grunt在前端工具中算是很有用的一个工具。 想一想如果没有这个工具,我们需要手动新建一个压缩代码后的文件夹,每次修改原始文件,都要手动压缩一下,再保存到压缩后的文件夹,想想都要疯掉。所以,grunt前端必不可少。
128 0
grunt入门笔记
|
数据库 数据库管理 Python
Python:masonite初体验TodoList
Python:masonite初体验TodoList
230 0
Python:masonite初体验TodoList
|
缓存 中间件 Ruby
Sinatra源码学习【上】
Sinatra是一个ruby的轻量级Web框架,这这个框架总共就1000多行代码,非常简洁,值得一读。 一、Sinatra组成 Sinatra的主要实现的代码在base.rb中,主要有以下几个部分: Request:继承于Rack::Request,用于描述一个请求,通过这个类可以很方便获取到请求
287 0
|
JSON 缓存 NoSQL
Bottle 源码阅读
bottle是一个简单的python-web服务框架,可以和其它WSGI服务组合提供web服务。它最大的特色是所有代码都在单个文件中,这样限制了项目的代码量不会爆炸,同时又仅依赖python标准库,是个不错的学习项目,我们一起来阅读一下吧。
338 0
|
C# Python 数据格式
Python3 与 NetCore 基础语法对比(Function专栏)
Jupyter最新排版:https://www.cnblogs.com/dotnetcrazy/p/9175950.html 昨晚开始写大纲做demo,今天牺牲中午休息时间码文一篇,希望大家点点赞 O(∩_∩)O NetCore:https://github.
1777 0
|
Apache Ruby Ubuntu