Статьи

Изучение стойки

Если вы программист на Ruby, который занимался любой веб-разработкой, вы почти наверняка использовали Rack , знаете ли вы это или нет, так как это основа, на которой строится большинство веб-фреймворков Ruby (Rails, Sinatra и т. Д.). на. Давайте углубимся в некоторые основные концепции Rack и даже создадим небольшое приложение или два.


Стойка это несколько вещей, на самом деле:

  • интерфейс веб-сервера
  • протокол для создания и создания веб-приложений
  • коллекция утилит промежуточного программного обеспечения

Что приятно в Rack, так это то, что он предоставляет стандартизированный способ для приложений Ruby общаться с веб-серверами, абстрагировать работу сервера (прослушивание порта, принятие соединений, анализ HTTP-запросов и ответов и т. Д.), Чтобы вы могли сосредоточиться на том, что делает ваше приложение.


Протокол Rack очень прост: приложение Rack — это просто объект Ruby с методом call . Этот метод должен принимать хеш среды, описывающий входящий запрос, и возвращать массив из трех элементов в виде: [status, headers, body] , где:

  • status — это код статуса HTTP.
  • headers — это хеш HTTP-заголовка для ответа.
  • body — это фактическое тело ответа (например, HTML, который вы хотите
    дисплей). Тело также должно отвечать each .

Самый простой способ понять протокол Rack — взглянуть на некоторый код.

Во-первых, получите гем стойки и создайте каталог:

1
2
3
$ gem install rack
$ mkdir hellorack
$ cd hellorack

Теперь создайте файл с именем config.ru и заполните его следующим config.ru :

01
02
03
04
05
06
07
08
09
10
11
12
class Hello
  def self.call(env)
    [ 200, # 200 indicates success
      {«Content-Type» => «text/plain»}, # the hash of headers
      [«Hello from Rack!»] # we wrap the body in an Array so
                                        # that it responds to `each`
    ]
  end
end
 
# Tell Rack what to run our app
run Hello

Сохраните файл, откройте свой терминал и выполните команду rackup :

1
2
3
4
$ rackup
[2012-12-21 17:48:38] INFO WEBrick 1.3.1
[2012-12-21 17:48:38] INFO ruby 1.9.2 (2011-07-09) [x86_64-darwin11.0.1]
[2012-12-21 17:48:38] INFO WEBrick::HTTPServer#start: pid=1597 port=9292

Несколько нижних строк вывода в приведенном выше коде сообщают, что Rack запускает ваше приложение на порту 9292, используя встроенный веб-сервер Ruby WEBrick. В браузере укажите http: // localhost: 9292, чтобы увидеть приветственное сообщение от Rack.

Убейте приложение (ctrl-c) и давайте поговорим о том, что здесь происходит.

Когда вы запускаете команду rackup , Rack ищет rackup конфигурации rackup (условно называемый config.ru , но вы можете называть его как угодно). Затем он запускает веб-сервер (по умолчанию WEBrick) и запускает ваше приложение.

Этот протокол является основой, на которой строятся популярные фреймворки, такие как Rails и Sinatra. Они выполняют функциональность слоя, такую ​​как рендеринг шаблонов, диспетчеризация маршрутов, управление соединениями с базой данных, согласование контента и т. Д. Поверх этой основной абстракции.

Как они это делают, это то, что подводит нас к концепции промежуточного программного обеспечения.


Промежуточное ПО дает вам возможность создавать приложения Rack вместе.

Промежуточное программное обеспечение (да, оно единственное и множественное число) — это просто приложение Rack, которое инициализируется с другим приложением Rack. Вы можете определить различное промежуточное программное обеспечение для выполнения разных заданий, а затем объединить их вместе для выполнения полезных задач.

Например, если у вас есть приложение на Rails (скорее всего, если вы разработчик на Ruby), вы можете cd в приложение и запустить rake middleware команды rake middleware чтобы увидеть, какое промежуточное программное обеспечение использует Rails:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ cd my-rails-app
$ rake middleware
use ActionDispatch::Static
use Rack::Lock
use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007fcc4481ae08>
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::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ParamsParser
use ActionDispatch::Head
use Rack::ConditionalGet
use Rack::ETag
use ActionDispatch::BestStandardsSupport
run MyRailsApp::Application.routes

Каждый запрос, поступающий в это приложение, начинается сверху этого стека, пузырится вниз, попадает в маршрутизатор внизу, который отправляет контроллеру, который генерирует какой-то ответ (обычно некоторый HTML), который затем пузырится обратно через стек перед отправкой обратно в браузер.


Ничто так не способствует пониманию новой концепции, как кодирование, поэтому давайте создадим очень простое промежуточное ПО, которое просто преобразует тело ответа в верхний регистр. Откройте наш файл config.ru и добавьте следующее:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class ToUpper
  # Our class will be initialize with another Rack app
  def initialize(app)
    @app = app
  end
 
  def call(env)
    # First, call `@app`
    status, headers, body = @app.call(env)
 
    # Iterate through the body, upcasing each chunk
    upcased_body = body.map { |chunk|
 
    # Pass our new body on through
    [status, headers, upcased_body]
  end
end
 
# This is the same Hello app from before, just without all the comments
class Hello
  def self.call(env)
    [ 200, {«Content-Type» => «text/plain»}, [«Hello from Rack!»] ]
  end
end
 
use ToUpper # Tell Rack to use our newly-minted middleware
run Hello

rackup команду rackup и посетите http: // localhost: 9292, чтобы увидеть наше новое промежуточное ПО в действии.

Здесь Rack создал приложение Rack, составленное из приложений ToUpper и Hello . Внутри Rack существует класс Builder который эффективно создает новое приложение, выполняя эквивалент:

1
2
app = ToUpper.new(Hello)
run app

Если бы присутствовало больше промежуточного программного обеспечения (как в стеке Rails), оно просто вложило бы их до конца:

1
2
3
4
5
6
use Middleware1
use Middleware2
use Middleware3
run MyApp
 
#=> Boils down to Middleware1.new(Middleware2.new(Middleware3.new(MyApp)))

Когда вы начинаете писать приложения и промежуточное ПО для Rack, управление массивом [status, headers, body] быстро становится утомительным.

Rack предоставляет несколько удобных классов, Rack::Request и Rack::Response , чтобы сделать жизнь немного проще.

Rack::Request оборачивает хэш env и предоставляет вам удобные методы для извлечения информации, которая может вам понадобиться:

01
02
03
04
05
06
07
08
09
10
11
12
def call(env)
  req = Rack::Request.new(env)
  req.request_method #=> GET, POST, PUT, etc.
  req.get?
  req.path_info # the path this request came in on
  req.session # access to the session object, if using the
  # Rack::Session middleware
  req.params # a hash of merged GET and POST params, useful for
  # pulling values out of a query string
 
  # … and many more
end

Rack::Response дополняет Rack::Request и предоставляет вам более удобный способ создания ответа. Например, наше приложение Hello можно переписать следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
class Hello
  def self.call(env)
    res = Rack::Response.new
 
    # This will automatically set the Content-Length header for you
    res.write «Hello from Rack!»
 
    # returns the standard [status, headers, body] array
    res.finish
 
    # You can get/set headers with square bracket syntax:
    # res[«Content-Type»] = «text/plain»
 
    # You can set and delete cookies
    # res.set_cookie(«user_id», 1)
    # res.delete_cookie(«user_id»)
  end
end

В этой статье мы рассмотрели основные концепции Rack, которых должно быть достаточно для того, чтобы вы лучше поняли, что скрыто под многими популярными фреймворками, а также, если вам это интересно, помогут вам промокнуть. в разработке напрямую с Rack.

Code является отличным учителем, и поэтому, если вы заинтересованы в Rack, я настоятельно рекомендую взглянуть на его источник . Он поставляется с множеством очень полезных встроенных утилит и промежуточного программного обеспечения (и еще с большим количеством на стеллажах ), которые вы можете использовать и учиться.