+4

Tìm hiểu về Ruby Rack

Nếu đã từng lập trình web với Ruby, bạn đã làm việc với Rack. Có thể nói Rack chính là nền tảng cho các web framework của Ruby như Sinatra, Rails hay Lotus,...

Rack cung cấp một minimal, modular, and adaptable interface để phát triển các ứng dụng web trong Ruby. Bằng cách gói các HTTP request và respone theo cách đơn giản nhất, nó hợp nhất và chọn lọc các API cho các web server, web framework và phần mềm trung gian(được gọi là middleware) vào một phương thức đơn là call

Tìm hiểu về Rack giúp ta có hiểu được cách thức hoạt động của các web framework, từ đó tùy biến chúng dễ dàng hơn.

Rack là gì?

Rack là:

  • a web server interface.
  • a protocol for buiiding and composing web applications.
  • a collection of middleware utilities.

Setup rack

Gem của Rack có sẵn tại rubygems.org, chúng ta có thể cài đặt như sau:

gem install rack

A Web Server Interface:

Rack cung cấp một cách chuẩn để ứng dụng Ruby giao tiếp được với web server. Tức là, Rack cung cấp một giao tiếp giữa các máy chủ Web hỗ trợ Ruby (Unicorn, Puma, Phusion Passenger, WEBrick,Thin,…) với các Ruby framework(Rails, Sinatra, Lotus, …).

The Protocol:

Một Rack application có cấu trúc rất đơn giản: nó là một Ruby Object, định nghĩa call method. call method có tham số đầu vào là một biến environment và trả về response với response là một array có 3 item [status, headers, body]:

  • status: is the HTTP status code.
  • headers: is a hash of HTTP headers for the response.
  • body: is the actual body of the response (e.g. the HTML you want to display). The body must also respond to each.

Một ví dụ đơn giản như sau:

Cách 1: Cách này sau khi code bạn cần phải start lại server.

# rack_app.rb
 require 'rack'
 app = Proc.new do |env|
    ['200', {'Content-Type' => 'text/html'}, ['Welcome to ruby rack!']]
end
 Rack::Handler::WEBrick.run app

Cách 2: Tạo file config.ru có nội dung:

# config.ru
run Proc.new { |env| ['200', {'Content-Type' => 'text/html'}, ['Welcome to ruby rack!']] }

Sau đó, mở terminal và chạy lệnh rackup như sau:

rackup config.ru

Hoặc

# config.ru
clasacks HelloRack
  def self.call(env)
    [200,
      {"Content-Type" => "text/plain"},
      ["Welcome to ruby rack!"]
    ]
  end
end

run HelloRack

Ở terminal, chỉ cần chạy lệnh

rackup
Listening on localhost:9292, CTRL+C to stop
127.0.0.1 - - [25/Jun/2016:03:28:56 +0700] "GET / HTTP/1.1" 200 - 0.0012
127.0.0.1 - - [25/Jun/2016:03:29:07 +0700] "GET / HTTP/1.1" 200 - 0.0012

Giải thích hoạt động của ứng dụng trên:

Ứng dụng này làm một nhiệm vụ rất đơn giản, với tất cả các request, trả về respose là đoạn text “Welcome to ruby rack!”, cùng với response code 200. Khi rackup ở trên, mặc định Rack sẽ dùng web server có sẵn của Ruby là WEBrick làm web server. WEBrick sẽ lắng nghe ở cổng 9292. Khi dùng browser access vào địa chỉ: http://localhost:9292 ta sẽ thấy nội dung trả về là dòng text: “Welcome to ruby rack!"

Khi WEBrick nhận request từ browser, nó sẽ gọi hàm call của class HelloRack mà ta viết ở trên, truyền vào biến env, lấy nội dung trả về của hàm này để trả về cho browser.

Middleware:

Middleware cung cấp cho bạn một cách để tạo các ứng dụng rack với nhau. Một middleware chỉ đơn giản là Rack appliaction được khởi tạo với một Rack application khác. Ta có thể định nghĩa những middleware khác nhau làm những việc khác nhau và sau đó có thể xếp chúng cùng nhau và cùng thực hiện một việc hữu ích khác.

Giữa server và framework, Rack tùy chỉnh ứng dụng theo middleware, một số middleware như sau: Rack::URLMap, to route to multiple applications inside the same process.

  • Rack::CommonLogger, for creating Apache-style logfiles.
  • Rack::ShowException, for catching unhandled exceptions and presenting them in a nice and helpful way with clickable backtrace.
  • Rack::File, for serving static files.

... và còn rất nhiều middleware khác.

Khi bạn có 1 ứng dụng Rails, bạn có thể mở terminal lên để kiểm tra những middleware mà ứng dụng đó đang sử dụng bằng lệnh rake middleware như sau:

$my_app rake middleware
use Rack::Sendfile
use ActionDispatch::Static
use Rack::Lock
use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x00000004e6d5f8>
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use ActionDispatch::DebugExceptions
use ActionDispatch::RemoteIp
use ActionDispatch::Reloader
use ActionDispatch::Callbacks
use ActiveRecord::Migration::CheckPending
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ParamsParser
use Rack::Head
use Rack::ConditionalGet
use Rack::ETag
use Warden::Manager
use OmniAuth::Strategies::Facebook
use OmniAuth::Strategies::Google
run MyApp::Application.routes

Ví dụ về sử dụng middleware như sau:

class ToUpper
  def initialize(app)
    @app = app
  end

  def call(env)
    status, headers, body  = @app.call(env)
    upcased_body = body.map { |chunk| chunk.upcase }
    [status, headers, upcased_body]
  end
end

class Hello
  def self.call(env)
    [ 200, {"Content-Type" => "text/plain"}, ["Hello from Rack!"] ]
  end
end

use ToUpper
run Hello

Như vậy với khả năng mở rộng của Rails bạn có thể dễ dàng thêm những middleware custom phù hợp với mục đích sử dụng. Hi vọng, qua bài viết này các bạn sẽ có thêm kiến thức với Rack và Rack Middleware.

Tham khảo:

https://github.com/rack/rack

http://www.rubydoc.info/github/rack/rack

http://code.tutsplus.com/tutorials/exploring-rack--net-32976


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.