0

Tìm hiểu Ruby Rack

1. Giới thiệu

Rack provides a minimal interface between webservers that support Ruby and Ruby frameworks.

Rack là interface giúp web server và web framework giao tiếp với nhau. Webserver ở đây có thể là WEBrick, Thin, Unicorn, Puma, và web framework có thể là Rails, Sinatra, …

2. Cấu trúc ứng dụng Rack

Rack application đơn giản là một Ruby Object, định nghĩa một hàm có tham số là một biến environment và trả về response. Response là một array có 3 item:

  • HTTP response code
  • Header
  • Body của response

Ta thử viết một ứng dụng Rack đơn giản:

Tạo file simplerack.rb:

# simplerack.rb

require 'rack'

app = Proc.new do |env|
    ['200', {'Content-Type' => 'text/html'}, [env.inspect]]
end

Rack::Handler::WEBrick.run app

Hoặc, tạo file config.ru:

# config.ru

run Proc.new { |env| ['200', {'Content-Type' => 'text/html'}, ['get rack\'d']] }

Nếu chưa cài gem rack:

$ gem install rack

Chạy ứng dụng:

$ ruby simple_rack.rb

Hoặc,

$ rackup config.ru

Kết quả:

[2016-05-24 20:35:41] INFO  WEBrick 1.3.1
[2016-05-24 20:35:41] INFO  ruby 2.1.2 (2014-05-08) [x86_64-linux]
[2016-05-24 20:35:41] INFO  WEBrick::HTTPServer#start: pid=21808 port=8080

Giải thích

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 (ở đây ta hoàn toàn có thể config để dùng các web server khác). Khi WEBrick nhận request từ browser, nó sẽ lấy nội dung trả về của Proc ta định nghĩa trong file trên để trả về cho browser.

WEBrick sẽ lắng nghe ở cổng 8080. Trong ví dụ trên, khi dùng browser access vào địa chỉ: http://localhost:8080 ta sẽ thấy nội dung trả về là nội dung biến env cùng với response code 200: Trong đó có một số key cần chú ý:

  • PATH_INFO: path của request. Mặc định sẽ là /
  • QUERY_STRING: params của request
  • REQUEST_METHOD: http method, GET, POST,…

Thử access bằng địa chỉ: http://localhost:8080/index.php?id=1010 ta sẽ thấy các value tương ứng với các key trên:

  • PATH_INFO: /index.php
  • QUERY_STRING: id=1010
  • REQUEST_METHOD: GET

3. Rack middleware

Ta có thể nối nhiều Rack application lại với nhau bằng Rack middle, ouput của Rack application sẽ là input của application khác. Việc này cung cấp tính mềm déo cho ứng dụng Rack, ta có thể thêm hoặc bớt các middleware theo ý mình mà không sợ ảnh hưởng đến middleware có sẵn.

Ví dụ điển hình nhất chính là Rails. Rails là một Rack application được tạo thành bởi nhiều Rack middleware. Chẳng hạn:

Rails::Rack::Logger
ActiveRecord::QueryCache
ActionDispatch::Cookies
ActionDispatch::Session::CookieStore
ActionDispatch::ParamsParser
Rails.application.routes

Để hiểu rõ hơn, ta viết ứng dụng SimpleRack với 2 middleware như sau:

# middleware.ru
class Logger
  def initialize
    @app = app
  end

  def call(env)
    status, header, body = @app.call(env)
    body.unshift("Info: This is log of Logger middleware\n")

    [status, header, body]
  end
end

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

use Logger
run SimpleRack

Thứ tự thực hiện của ứng dụng Rack trên như sau:

Request --> WEBrick --> Logger --> SimpleRack --> Logger --> Browser

Logger sẽ pass request cho SimpleRack xử lý, SimpleRack xử lý xong trả response lại cho Logger, Logger append một dòng log vào response và trả response này về lại cho browser

Vì thế khi access địa chỉ http://localhost:8080 ta thấy ngoài nội dung “Hello from Rack!” còn thêm 1 dòng “Info: This is log of Logger middleware”, dòng này chính là kết quả việc thực hiện middleware Logger.

Bên cạnh các chức năng cơ bản trên, Rack còn implement sẵn một số hàm helper như parse params, build response,… Chi tiết hơn có thể tham khảo ở document của Rack tại: http://www.rubydoc.info/github/rack/rack hoặc http://rack.github.io/

Nguồn: http://hawkins.io/2012/07/rack_from_the_beginning/


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí