分享 Rack, 我忽视你了 [已更新]

liwei78 · 2013年10月25日 · 最后由 liwei78 回复于 2013年12月09日 · 9860 次阅读
本帖已被管理员设置为精华贴

写在前面: RubyConfChina 结束了,感觉组织者的辛苦付出。期待明年带给我们更多的启示。另:让我们买本英语 500 句,每天学一点吧。

什么是 Rack

Rack provides a minimal, modular and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between (the so-called middleware) into a single method call.

大意:Rack 是个 api,这个 api 会调用一个方法,它是 call()。

什么是 Rack Application?

A Rack application is an Ruby object (not a class) that responds to call. It takes exactly one argument, the environment and returns an Array of exactly three values: The status, the headers, and the body.

大意:Rack App 需要提供一个方法,它就是 call()。

一个误解:Rack 是 web server 吗?

答:它不是。

  1. 一个浏览器请求
  2. web server 将请求交给了 Rack
  3. Rack 告诉了 app
  4. app 想了想,告诉 Rack 我的返回结果是什么
  5. Rack 告诉 web server 它要的结果
  6. web server 告诉浏览器一个可解析的结果

Rack 为我做了什么?让 Sprockets 代表大伙发个言。

看看 Sprockets

之前我对 Sprockets 的概念完全被 Rails 给代替了,那么注意下面标注的文字,原来只是 Rails 替我做了额外的事情,我没有察觉。

You'll need an instance of the Sprockets::Environment class to access and serve assets from your application. Under Rails 3.1 and later, YourApp::Application.assets is a preconfigured Sprockets::Environment instance. For Rack-based applications, create an instance in config.ru.

那么,我如果自己单独使用 Sprockets 呢?

If you are using Sprockets with a Rack application, you will need to mount the environment yourself. A good way to do this is with the map method in config.ru:

require 'sprockets'
map '/assets' do
  environment = Sprockets::Environment.new
  environment.append_path 'app/assets/javascripts'
  environment.append_path 'app/assets/stylesheets'
  run environment
end

map '/' do
  run YourRackApp
end

Sprockets 可以支持 SCSS/SASS,LESS,CoffeeScript,甚至.scss.erb。

我能用 Rack 做什么?

注意那个不起眼的 config.ru,我可以用它来写一个自己的 Ruby 框架。当然啦,这个框架现在什么也不做。

# config.ru
require ::File.expand_path('../my_app.rb',  __FILE__) # 这句话copy自Rails,吼吼
run MyApp::Application
# my_app.rb
module MyApp
  class Application
    def self.call(env)
      [200, {"Content-Type" => "text/html"}, ["<h1>It's My App</h1>", '<p>Yeah!!!</p>']]
    end
  end
end

rackup -s WEBrick -p 1212

如果你看过这篇文章,那么你会发现,我们熟知的 Rails 启动方式,还可以这样完成:

# Rails.root/config.ru
require ::File.expand_path('../config/environment', __FILE__)

use Rack::Debugger
use Rack::ContentLength
run Rails.application

写这篇文章的缘由,是在开发一个功能时,想到它可以包装成一个 gem,而后有看了Rails Guides: Getting Started with Engines中文在这里,这之后有了对 Rails 进行解构的想法,而后,便是更加清楚的意识到 Rack 的存在了。

那么,sinatra,和其他同类型的 Rack-based app(非 Rails),都是我们可以尝试的选择。

继续对 Rails 解构,我们还会发现什么?

当我们rake middleware的时候,我们可以看到 Rails 加载了哪些 middleware,这些不是写在 Gemfile 里的,但是他们可以来自 gem。这就有点奇怪的感觉了,不是么?

如果我们选择 sinatra,选择一些自己要使用的 gem,再挑选一些 middleware,我们就可以搭建一个 app 了。比如,一个管理 jekyll 的 app blog。

写在后面

这篇短文的意图,是想通过 Rails 的解构,对 Rack 和其他 Rack-based App 有一个清楚的了解,当我们选择功能方案的时候,会从另外一些角度,选择我们合适的实现途径。Rails 给我们的贡献,就像 Prem 在 RubyConf 上讲到的,我们可以看看,把 Rails 的哪些东西可以放到我们的项目里。

这篇博文是两次完成的,因为期间要参加 RubyConfChina,所以在之前把半成品放了出去,听听大家的意见。回来后发现了一些新的资源,一并补充进来。再次感谢提出意见的 ruby-china.org 的小伙伴们。

参考资料

http://guides.rubyonrails.org/v3.2.13/rails_on_rack.html

Ruby on Rack #1 - Hello Rack!

Ruby on Rack #2 - The Builder

Rails meets Sinatra

Rails meets Sinatra #2 - Mix n' Match

What is ‘Rack’ in Ruby/Rails?

Rack Doc

sinatra

Rails on Rack

(转载) Rails 與 Merb 合併背後的故事

原文地址:里克的自习室:Rack, 我忽视你了

Paste has a pony, rack has a lobster!

#1 楼 @krazy 没懂。。。。。。😳

LZ 头像一看,就知道是经常撸啊撸的

Ruby 版的 WSGI 嘛……不过库包装得很不错……

一点寒芒先到!

随后枪出如龙!

@Asaka 我怎么记得是一朵菊花先到...

恩恩。。。我收下了,研究中。。 #11 楼 @nouse

咦??酒店没有 wifi,幸好带了个 tp-link。。。然后。。。。我竟然被加精了,谢谢版主,鼓励原创。

花了很长时间 翻译了这篇文章 英文不好, 正在努力中 翻译不好的地方请多指教http://kqis.me/ruby/2013/09/26/rack/

#14 楼 @kimbo 鼓掌鼓掌!!!!

‘一个误解:Rack 不是 web server’ 请问,Rack 到底是不是 web server 呢?

#17 楼 @liwei78 我的意思是,你这句话的表述有歧义,看了还是不明白到底是不是。

#18 楼 @steveLTN 谢谢指正,我的标题的确表意不清楚,已经改正。

:smile 嗯,还不错

require 'rack'
Rack::Handler.constants

介绍 rack 和 app 衔接的多,介绍 server 和 rack 的 Handler 衔接少,@liwei78可以将这部分加上去

#21 楼 @chq 好的。我看下。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号