一、什么是Rack
Rack是ruby应用服务器和Rack应用程序之间的接口,
这里面Ruby应用服务器可以是Webrick、thin等,Rack应用程序可以是rails、Sinatra等(其实 现在主流的ruby的Web框架都是基于Rack的)。在上图中,当用户的请求到达应用服务器时,应用服务器会调用rack对请求进行包装,然后在 调用你的rack应用程序,rack程序可以对请求进行分析、处理,并利用rack的响应设施进行输出,rack会将用户响应作为输出返回给ruby应用服务器。
二、为什么要用Rack
1、提供一个广泛支持的标准接口
Rack提供了一个标准接口,便于应用程序和应用服务器进行交互,一个Rack应用可以被任何和Rack兼容的应用服务器调用,最明显的一个例子,我们开发的rails应用或者Sinatra应用可以直接使用Webrick或者thin等服务器启动,不用做什么修改,非常方便。
2、模块化、高可重用性
Rack利用中间件实现最大程度模块化,从而提高Web应用程序部件的可重用性,从而提高开发效率
Rack中间件对Ruby Web框架也有很深远的影响:
3、简单
Rack标准简单,这就很容易让用户实现一个Web服务器或者Web框架
三、一个简单的Rack应用程序
1、Rack尝鲜
一个Rack程序应该符合如下条件:
require 'rack'
classMyApp
defcall(env)
[200, {}, ["this is my app"]]
end
end
my_app =MyApp.new
Rack::Handler::WEBrick.run my_app, :Port => 3000
运行这段代码,在浏览器中访问 http://localhost:3000
上面这段代码就是我们实现的一个最简单的Rack应用,我们实现了一个类MyApp,他只有一 个call方法,此方法接受一个参数,返回一个数组,此数据包含status、header、body,在这 里呢,我使用WEBrick来启动这个应用,同样我也可以使用thin来启动,那么最后一句话就变成:
Rack::Handler::thin.run my_app, :Port => 3000
我们在前面说了,目前主流的ruby应用服务器都是兼容Rack接口的,其实这里呢Rack使用了 一种叫Handler(句柄)的机制来实现对众多应用服务器的支持,这些句柄都是在 Rack::Handler命名空间下的,我们可以看到这些类:
Rack::Handler::CGI
Rack::Handler::FastCGI
Rack::Handler::Mongrel
Rack::Handler::EventedMongrel
Rack::Handler::SwiftipliedMongrel
Rack::Handler::WEBrick
Rack::Handler::LSWS
Rack::Handler::SCGI
Rack::Handler::Thin
也就是说Rack缺省下对上面这些服务器支持的。
2、Rack的环境
继续回到我们刚才的应用中来,刚才代码中我们call方法接受一个参数env,那么这个env到底有什么东⻄呢,我们修改下之前的代码:
require 'rack'
classMyApp
defcall(env)
body =get_env(env)
[200, {"Content-type" => "text/html"}, [body]]
end
defget_env(env)
env.map {|k, v| "#{k} => #{v}" }.sort.join("<br/>")
end
end
my_app =MyApp.new
Rack::Handler::WEBrick.run my_app, :Port => 3000
这段代码中我们将env的值放到body中,在浏览器中访问http://localhost:3000我们可以看到如下内容:
GATEWAY_INTERFACE => CGI/1.1HTTP_ACCEPT => text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 HTTP_ACCEPT_ENCODING =>gzip, deflate, sdch
HTTP_ACCEPT_LANGUAGE => zh-CN,zh;q=0.8HTTP_CACHE_CONTROL => max-age=0
HTTP_CONNECTION => keep-alive
HTTP_COOKIE => remember_token=3E02V5zkb8eAmrUKckE69A
HTTP_HOST => localhost:3000HTTP_UPGRADE_INSECURE_REQUESTS => 1HTTP_USER_AGENT => Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36 HTTP_VERSION => HTTP/1.1PATH_INFO => /QUERY_STRING =>REMOTE_ADDR => ::1REMOTE_HOST =>localhost
REQUEST_METHOD =>GET
REQUEST_PATH => /REQUEST_URI => http://localhost:3000/SCRIPT_NAME =>SERVER_NAME =>localhost
SERVER_PORT => 3000SERVER_PROTOCOL => HTTP/1.1SERVER_SOFTWARE => WEBrick/1.3.1 (Ruby/2.0.0/2015-02-25)
rack.errors => #rack.hijack => #<proc:0x007f843a9054a0@ users=”” yangye=”” .rvm=”” gems=”” ruby- 2.0.0-p643=”” rack-1.6.4=”” lib=”” rack=”” handler=”” webrick.rb:76=”” (lambda)=””> rack.hijack? => true
rack.hijack_io =>rack.input => #rack.multiprocess => false rack.multithread => true rack.run_once => false rack.url_scheme => http rack.version => [1, 3]
我们可以看出来,env的key主要包含大写的CGI的头,以及rack自己的环境变量 修改我们的url,我们可以看到返回的env中的一些键值会有不同的变化,各位自己尝试下
从上面我们可以看出来,我们编写一个rack应用程序,可以通过env获取用户的请求的方法, 路径名,查询参数,从而调用不同的应用程序去处理,非常高效的去实现各种各样的应用,但 是如果直接存取环境参数会很麻烦,我们还得自己去解析查询参数,维护用户会话信息,不过 好在rack本身提供了丰富的API帮我们解决了这些问题,下面来看两个重要的类Request和 Response。
3、常用的类
Request
这个类的定义是在rack-1.6.4/lib/rack/request.rb 我们要创建一个Request对象很简单,只需要将env传给其构造函数即可 Rack::Request.new(env) 不难想象,Request里面的诸多方法其实就是对env的解析,感兴趣可以去阅读下源码 Response
这个类的定义是在/rack-1.6.4/lib/rack/response.rb。
创建一个Response对象也很简单:Rack::Response.new
这个类的构造函数如下:
def initialize(body=[], status=200, header={})
@status =status.to_i
@header =Utils::HeaderHash.new.merge(header)
@chunked = CHUNKED ==@header[TRANSFER_ENCODING]
@writer = lambda { |x| @body <<x }
@block =nil
@length =0
@body =[]
ifbody.respond_to? :to_str
write body.to_str
elsif body.respond_to?(:each)
body.each { |part|write part.to_s }
else
raise TypeError, "stringable or iterable required"end
yield self ifblock_given?
end
也就是说,我们在实例化对象时也可以直接传递status、header、body或者我们先实例化对象然后在修改这三个属性。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://www.cnblogs.com/alalazy/p/16260547.html
内容来源于网络,如有侵权,请联系作者删除!