Що таке програмне забезпечення Rack?


266

Що таке програмне забезпечення Rack в Ruby? Я не зміг знайти жодного хорошого пояснення того, що вони означають під "програмним забезпеченням".


4
Є також путівник по RailsGuide, який всебічно висвітлює Rack, включаючи проміжне програмне забезпечення: guides.rubyonrails.org/rails_on_rack.html
xji

Велике спасибі команді PhusionPassenger, у їхньому блозі є добре пояснена стаття. rubyraptor.org / ...
Ламійський

Стійки і стійки проміжного шару пояснюються в ЦІЙ статті. Також пояснено про створення програми на основі стійки.
shashwat srivastava

Відповіді:


353

Стійка як дизайн

Посереднє програмне забезпечення Rack - це більше, ніж "спосіб фільтрації запиту та відповіді" - це реалізація структури дизайну конвеєра для веб-серверів за допомогою Rack .

Він дуже чітко розмежовує різні етапи обробки запиту - відокремлення питань є ключовою метою всіх добре розроблених програмних продуктів.

Наприклад, у Rack я можу мати окремі етапи роботи конвеєра:

  • Автентифікація : коли запит надходить, чи правильні дані про вхід користувачів? Як я підтверджую цю OAuth, HTTP Basic Authentication, ім'я / пароль?

  • Авторизація : "чи користувач уповноважений виконувати цю конкретну задачу?", Тобто захист на основі ролей.

  • Кешування : чи я вже обробив цей запит, чи можу я повернути кешований результат?

  • Прикраса : як я можу покращити запит, щоб покращити обробку нижче?

  • Моніторинг ефективності та використання : які статистичні дані я можу отримати від запиту та відповіді?

  • Виконання : реально обробити запит та надати відповідь.

Вміння розділяти різні етапи (і необов'язково включати їх) - це чудова допомога в розробці добре структурованих додатків.

Громада

Існує також чудова екосистема, що розвивається навколо Rack Middleware - ви повинні мати змогу знайти заздалегідь складені компоненти стійки, щоб виконати всі вищезазначені кроки та багато іншого. Перегляньте вікі Rack GitHub для переліку програмного забезпечення .

Що таке Посередництво?

Посереднє програмне забезпечення - жахливий термін, який стосується будь-якого програмного компонента / бібліотеки, який допомагає, але безпосередньо не бере участі у виконанні якогось завдання. Дуже поширеними прикладами є реєстрація, аутентифікація та інші загальні компоненти горизонтальної обробки . Це, як правило, речі, які потрібні всім у кількох програмах, але не надто багато людей зацікавлені (або повинні бути) у створенні самих себе.

Більше інформації


Одне мені незрозуміло: чи всі проміжні програми обмінюються однаковими даними? Чи можна їх розділити (тобто пісочницю) для безпеки?
Брайан Армстронг,

2
Rack є частиною вашої програми, тому всі компоненти програмного забезпечення входять в одну і ту ж копію запиту, і кожен може змінювати його будь-яким способом. AFAIK, немає ніякого способу пісочниці їх так само, як немає можливості пісочниці одного об'єкта від іншого в рамках одного і того ж процесу (спроби в Ruby sandboxing незважаючи на це).
Кріс МакКолі

1
І чи розумієте Ви, що Рейка відрізняється від Рейка.
Маніш Шрівастава

1
Мені подобається думати про проміжне програмне забезпечення як про те, що знаходиться в середині мого додатка між тим, що я кодував, і тим, що йде на сервер і з нього ... що розміщено на рейковій площі. Причина, що термін «програмне забезпечення для стійки» є заплутаним, як ми всі знаємо, тому, що саме Конфуцій написав усі оригінальні програмні засоби для стійки більше 2000 років тому. У Франції.
LpLrich

74

Перш за все, Rack - це рівно дві речі:

  • Конвенція про веб-сервер
  • Самоцвіт

Rack - Інтерфейс веб-сервера

Самі основи стійки - це проста умова. Кожен веб-сервер, сумісний із стійкою, завжди буде викликати метод виклику на об'єкт, який ви йому надаєте, і обслуговуватиме результат цього методу. Rack вказує, як саме повинен виглядати цей метод виклику та що він повинен повертати. Це стійка.

Давайте спробуємо просто. Я буду використовувати WEBrick як веб-сервер, сумісний із стійкою, але будь-який з них буде робити. Створимо просту веб-програму, яка повертає рядок JSON. Для цього ми створимо файл під назвою config.ru. Конфігурація.ru автоматично буде викликана командною стійкою команди rack gem, яка просто запустить вміст config.ru на веб-сервері, сумісному з стійкою. Тож додамо у файл config.ru наступне:

class JSONServer
  def call(env)
    [200, {"Content-Type" => "application/json"}, ['{ "message" : "Hello!" }']]
  end
end

map '/hello.json' do
  run JSONServer.new
end

Як зазначено в конвенції, наш сервер має метод, який називається call, який приймає хеш середовища і повертає масив із формою [статус, заголовки, тіло] для обслуговування сервера. Давайте спробуємо це, просто зателефонувавши в рейк Сервер, сумісний із стійкою, який може бути встановлений за замовчуванням, можливо, WEBrick або Mongrel запустяться і негайно чекають подання запитів.

$ rackup
[2012-02-19 22:39:26] INFO  WEBrick 1.3.1
[2012-02-19 22:39:26] INFO  ruby 1.9.3 (2012-01-17) [x86_64-darwin11.2.0]
[2012-02-19 22:39:26] INFO  WEBrick::HTTPServer#start: pid=16121 port=9292

Давайте перевіримо наш новий сервер JSON шляхом завивки або відвідування URL-адреси http://localhost:9292/hello.jsonта вуаля:

$ curl http://localhost:9292/hello.json
{ message: "Hello!" }

Це працює. Чудово! Це основа для кожної веб-рамки, будь то Rails або Sinatra. У якийсь момент вони реалізують метод виклику, опрацьовують весь рамковий код і нарешті повертають відповідь у типовій формі [статус, заголовки, тіло].

Наприклад, у Ruby on Rails стійка запитів потрапляє до ActionDispatch::Routing.Mapperкласу, який виглядає приблизно так:

module ActionDispatch
  module Routing
    class Mapper
      ...
      def initialize(app, constraints, request)
        @app, @constraints, @request = app, constraints, request
      end

      def matches?(env)
        req = @request.new(env)
        ...
        return true
      end

      def call(env)
        matches?(env) ? @app.call(env) : [ 404, {'X-Cascade' => 'pass'}, [] ]
      end
      ...
  end
end

Таким чином, Rails перевіряє, залежно від хеш-коду, якщо збігається будь-який маршрут. Якщо це так, він передає env-хеш додатку для обчислення відповіді, інакше він негайно відповідає 404. Отже, будь-який веб-сервер, який відповідає конвенції рейкового інтерфейсу, може обслуговувати повністю продутий додаток Rails.

Посереднє програмне забезпечення

Rack також підтримує створення проміжних шарів. Вони в основному перехоплюють запит, роблять щось з ним і передають його далі. Це дуже корисно для різнобічних завдань.

Скажімо, ми хочемо додати журнал на наш сервер JSON, який також вимірює тривалість запиту. Ми можемо просто створити реєстратор середнього програмного забезпечення, який робить саме це:

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

  def call(env)
    @start = Time.now
    @status, @headers, @body = @app.call(env)
    @duration = ((Time.now - @start).to_f * 1000).round(2)

    puts "#{env['REQUEST_METHOD']} #{env['REQUEST_PATH']} - Took: #{@duration} ms"
    [@status, @headers, @body]
  end
end

Коли він створюється, він зберігає собі копію фактичної програми-стійки. У нашому випадку це екземпляр нашого JSONServer. Rack автоматично викликає метод виклику в середньому програмному забезпеченні і очікує повернення [status, headers, body]масиву, як і наш JSONServer повертається.

Отже, в цьому середньому програмному забезпеченні приймається початкова точка, потім здійснюється фактичний виклик JSONServer @app.call(env), потім реєстратор виводить запис журналу і, нарешті, повертає відповідь як [@status, @headers, @body].

Щоб наш маленький rackup.ru використовував це проміжне програмне забезпечення, додайте до нього RackLogger так:

class JSONServer
  def call(env)
    [200, {"Content-Type" => "application/json"}, ['{ "message" : "Hello!" }']]
  end
end

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

  def call(env)
    @start = Time.now
    @status, @headers, @body = @app.call(env)
    @duration = ((Time.now - @start).to_f * 1000).round(2)

    puts "#{env['REQUEST_METHOD']} #{env['REQUEST_PATH']} - Took: #{@duration} ms"
    [@status, @headers, @body]
  end
end

use RackLogger

map '/hello.json' do
  run JSONServer.new
end   

Перезавантажте сервер і вуаля, він виводить журнал на кожен запит. Rack дозволяє додавати декілька середніх програм, які викликаються в порядку їх додавання. Це просто чудовий спосіб додати функціональність, не змінюючи ядро ​​додатку стійки.

Стійка - Самоцвіт

Хоча стійка - в першу чергу - умовна умова, вона також є дорогоцінним каменем, який забезпечує чудову функціональність. Один з них ми вже використовували для нашого сервера JSON, команду rackup. Але є більше! Стійка дорогоцінних каменів надає мало додатків для безлічі випадків використання, наприклад, для обслуговування статичних файлів або навіть цілих каталогів. Подивимося, як ми обслуговуємо простий файл, наприклад, дуже основний HTML-файл, розміщений у htmls / index.html:

<!DOCTYPE HTML>
  <html>
  <head>
    <title>The Index</title>
  </head>

  <body>
    <p>Index Page</p>
  </body>
</html>

Ми, можливо, хочемо подати цей файл із кореня веб-сайту, тому додамо наступне на наш config.ru:

map '/' do
  run Rack::File.new "htmls/index.html"
end

Якщо ми відвідуємо, http://localhost:9292ми бачимо, що наш html-файл ідеально відображений. Це було легко, правда?

Додамо цілий каталог файлів javascript, створивши кілька файлів javascript під / javascripts і додавши до config.ru наступне:

map '/javascripts' do
  run Rack::Directory.new "javascripts"
end

Перезапустіть сервер і відвідайте, http://localhost:9292/javascriptі ви побачите список усіх файлів javascript, які ви зараз можете включити прямо з будь-якого місця.


3
Але не програмне забезпечення Rack?
Rup

1
Якщо ви не знаєте, що таке стійка, ви точно дізнаєтеся, що це таке і як ним користуватися, прочитавши цю публікацію в блозі. Дуже хороша. Як не дивно, посилання на офіційну документацію про стійки в кінці посту більше не доступна!
Колін

Ваше право, дякую. Я включив вміст у публікацію та видалив мертве посилання.
Томас Фанкхаузер

Я б сказав, що це не конвенція. це інтерфейс, контракт, чітко визначений для моделі на відповідь на запит
Рон Кляйн

20

У мене була проблема з розумінням Rack себе протягом великої кількості часу. Я це повністю зрозумів лише після роботи над створенням цього мініатюрного веб-сервера Ruby . Я поділився своїми знаннями про Rack (у формі історії) тут, у своєму блозі: http://gauravchande.com/what-is-rack-in-ruby-rails

Відгуки більш ніж вітаються.


13
Відповіді, що стосуються лише посилань, відмовляються від переповнення стека , оскільки якщо ресурс, на який посилається, в майбутньому стає недоступним, відповідь стає марною. Принаймні узагальнюйте відповідні пункти своєї публікації блогу та додайте їх до цієї відповіді.

Дякую за ваш пост Я дуже початківець програміст Rails, і я зрозумів концепцію стійки з Вашим чітким повідомленням.
Едуардо Рамос

Чудова публікація в блозі. Інші відповіді здаються дещо більш викривленими ІМО.
Clam

Яке дивовижне пояснення. Спасибі, Гаурав.
rovitulli

7

config.ru мінімальний приклад для виконання

app = Proc.new do |env|
  [
    200,
    {
      'Content-Type' => 'text/plain'
    },
    ["main\n"]
  ]
end

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

  def call(env)
    @status, @headers, @body = @app.call(env)
    [@status, @headers, @body << "Middleware\n"]
  end
end

use(Middleware)

run(app)

Бігайте rackupі відвідуйте localhost:9292. Вихід:

main
Middleware

Тож зрозуміло, що Middlewareобгортає і називає основний додаток. Тому він може попередньо обробити запит і будь-яким чином опрацювати відповідь.

Як пояснено на веб- сайті: http://guides.rubyonrails.org/rails_on_rack.html#action-dispatcher-middleware-stack , Rails використовує середню програму Rack для великої її функціональності, і ви можете додати свої власні config.middleware.useсімейні методи.

Перевага впровадження функціональності в проміжне програмне забезпечення полягає в тому, що ви можете повторно використовувати його на будь-якій основі Rack, таким чином, всі основні Ruby, а не лише Rails.


6

Посереднє програмне забезпечення для стійки - це спосіб фільтрації запиту та відповіді, що надходить у вашу програму. Компонент посередництва знаходиться між клієнтом і сервером, обробляючи вхідні запити та вихідні відповіді, але це більше, ніж інтерфейс, який можна використовувати для спілкування з веб-сервером. Він використовується для групування та замовлення модулів, які зазвичай є класами Ruby, і вказує залежність між ними. Модуль проміжного програмного забезпечення для Rack повинен: - мати конструктор, який приймає наступне додаток у стеці як параметр, - відповідати методу "call", який приймає хеш середовища як параметр. Повертається значення цього виклику - це масив: код стану, хеш середовища та тіло відповіді.


4

Я використовував програмне забезпечення Rack для вирішення декількох проблем:

  1. Ловля помилок синтаксичного розбору JSON за допомогою користувацького проміжного програмного забезпечення Rack та повернення добре відформатованих повідомлень про помилки, коли клієнт надсилає розбитий JSON
  2. Стиснення вмісту через Rack :: Deflater

Це дало досить елегантні виправлення в обох випадках.


2
Ця відповідь, хоча і є дещо корисною, насправді не стосується питання, що таке програмне забезпечення Rack Middleware .

Також ця відповідь є досить лише посиланням ...: P
Smar

4

Що таке стійка?

Rack забезпечує мінімальний інтерфейс між веб-серверами, що підтримують рамки Ruby та Ruby.

За допомогою Rack можна написати програму Rack.

Rack передає хеш-середовище (Hash, що міститься в HTTP-запиті від клієнта, що складається з заголовків, схожих на CGI), до вашої програми Rack, яка може використовувати речі, що містяться в цьому хеші, робити все, що завгодно.

Що таке додаток Rack?

Щоб використовувати Rack, ви повинні надати "додаток" - об'єкт, який відповідає #callметоду за допомогою параметра Hash Environment як параметр (як правило, визначений як env). #callповинен повернути масив рівно трьох значень:

  • код стану (наприклад , «200»),
  • Хеш заголовків ,
  • Response Body (який повинен відповісти методом на Ruby each).

Ви можете написати програму Rack, яка повертає такий масив - це буде відправлено назад вашому клієнту, Rack, у відповідь (це фактично буде екземпляр класу Rack::Response[натисніть, щоб перейти до документів]).

Дуже просте застосування в стійці:

  • gem install rack
  • Створіть config.ruфайл - Rack знає, що це шукати.

Ми будемо створювати крихітний Rack додаток , яке повертає відповідь (екземпляр Rack::Response) , який Відповідний Тіло являє собою масив , який містить рядок: "Hello, World!".

Ми запустимо локальний сервер за допомогою команди rackup.

Відвідавши відповідний порт у нашому браузері, ми побачимо "Привіт, світ!" винесені у вікно перегляду.

#./message_app.rb
class MessageApp
  def call(env)
    [200, {}, ['Hello, World!']]
  end
end

#./config.ru
require_relative './message_app'

run MessageApp.new

Запустіть локальний сервер rackupі відвідайте localhost: 9292, і ви побачите "Привіт, світ!" винесено.

Це не є вичерпним поясненням, але по суті, що тут відбувається, це те, що Клієнт (браузер) надсилає запит HTTP до Rack через ваш локальний сервер, а Rack створює екземпляр MessageAppта запускcall , передаючи в середовищі Hash як параметр метод ( envаргумент).

Rack приймає повернене значення (масив) і використовує його для створення екземпляра Rack::Responseі повертає його назад Клієнту. Браузер використовує магію для друку "Привіт, світ!" на екран.

До речі, якщо ви хочете побачити, як виглядає хеш-середовище, просто покладіть puts env під нього def call(env).

Як мінімум, те, що ви тут написали, - це програма Rack!

Взаємодія програми Rack взаємодіє з хешем вхідного середовища

У нашому маленькому додатку Rack ми можемо взаємодіяти з envхешем ( детальніше про хеш навколишнього середовища див. Тут ).

Ми реалізуємо можливість користувача вводити свій власний рядок запиту в URL-адресу, отже, ця рядок буде присутній у запиті HTTP, інкапсульованому як значення в одній з пар ключів / значень хеш середовища.

Наш додаток Rack отримає доступ до цього рядка запиту з хеш-середовища оточення та відправить його назад клієнту (у нашому веб-переглядачі, в даному випадку) через орган у відповіді.

З Документів Rack на хеш-середовищі: "QUERY_STRING: Частина URL-адреси запиту, яка відповідає?, Якщо така є. Може бути порожньою, але завжди обов'язковою!"

#./message_app.rb
class MessageApp
  def call(env)
    message = env['QUERY_STRING']
    [200, {}, [message]]
  end
end

Тепер, rackupі відвідайте localhost:9292?hello( ?helloце рядок запиту), і вам слід побачити "привіт", відображений у вікні перегляду.

Rack Middleware

Ми будемо:

  • вставити шматок Rack Middleware в нашу кодову - клас: MessageSetter,
  • хеш - середа вдарить цей клас першим і буде прийнятий в якості параметра: env,
  • MessageSetterвставить 'MESSAGE'ключ у хеш-код env, його значення буде, 'Hello, World!'якщо env['QUERY_STRING']воно порожнє; env['QUERY_STRING']якщо ні,
  • нарешті, він повернеться @app.call(env)- @appбути наступним додатком в «Стек»: MessageApp.

По-перше, версія "довгої руки":

#./middleware/message_setter.rb
class MessageSetter
  def initialize(app)
    @app = app
  end

  def call(env)
    if env['QUERY_STRING'].empty?
      env['MESSAGE'] = 'Hello, World!'
    else
      env['MESSAGE'] = env['QUERY_STRING']
    end
    @app.call(env)
  end
end

#./message_app.rb (same as before)
class MessageApp
  def call(env)
    message = env['QUERY_STRING']
    [200, {}, [message]]
  end
end

#config.ru
require_relative './message_app'
require_relative './middleware/message_setter'

app = Rack::Builder.new do
  use MessageSetter
  run MessageApp.new
end

run app

З документів Rack :: Builder ми це бачимоRack::Builder реалізує невеликий DSL для ітеративної побудови додатків Rack. Це в основному означає, що ви можете створити "стек", що складається з однієї або декількох середніх програм та додатка "нижнього рівня", на який потрібно відправляти. Усі запити, що надходять до вашої програми нижнього рівня, спочатку будуть оброблені вашими проміжними програмами.

#useвказує проміжне програмне забезпечення для використання в стеку. Посереднє програмне забезпечення приймає як аргумент.

Посереднє програмне забезпечення для стійки повинно:

  • мати конструктор, який приймає наступний додаток у стеку як параметр.
  • відповісти на callметод, який приймає хеш середовища як параметр.

У нашому випадку "Middleware" - MessageSetterце "конструктор" - initializeметод MessageSetter , "наступним додатком" в стеці є MessageApp.

Так ось, через те, що Rack::Builderробиться під кришкою, appаргумент методу MessageSetter's initializeє MessageApp.

(обведіть голову навколо вище, перш ніж рухатися далі)

Отже, кожен фрагмент Middleware по суті "передає" існуючий хеш-середовище до наступної програми в ланцюзі - так що у вас є можливість вимкнути цей хеш-середовище в середовищі Middleware, перш ніж передати його наступному додатку в стеку.

#runбере аргумент, що є об'єктом, який відповідає #callі повертає Rack Response (екземпляр Rack::Response).

Висновки

Використовуючи Rack::Builderви можете побудувати ланцюжки Middlewares, і будь-який запит до вашої програми буде оброблятися кожним Middleware по черзі, перш ніж остаточно обробити остаточний фрагмент у стеку (у нашому випадку MessageApp). Це надзвичайно корисно, оскільки воно розділяє різні етапи обробки запитів. З точки зору "розділення проблем", це не може бути набагато чистішим!

Ви можете побудувати "трубопровід запитів", що складається з декількох середніх програм, які стосуються таких речей, як:

  • Аутентифікація
  • Авторизація
  • Кешування
  • Прикраса
  • Моніторинг продуктивності та використання
  • Виконання (фактично обробляти запит та надати відповідь)

(вище пунктів від іншої відповіді на цю тему)

Ви часто будете бачити це в професійних додатках Sinatra. Sinatra використовує Rack! Дивіться тут для визначення того , що Сінатра IS !

Як остаточне зауваження, наше config.ruможе бути написане стильним стилем, створюючи абсолютно таку ж функціональність (і саме це ви зазвичай бачите):

require_relative './message_app'
require_relative './middleware/message_setter'

use MessageSetter
run MessageApp.new

А щоб більш чітко показати, що MessageAppробиться, ось його "довга" версія, яка прямо показує, що #callстворює новий екземпляр Rack::Response, з необхідними трьома аргументами.

class MessageApp
  def call(env)
    Rack::Response.new([env['MESSAGE']], 200, {})
  end
end

Корисні посилання


1

Стійка - Інтерфейс сервера для веб / додатків

Rack - це пакет Ruby, який надає інтерфейс для веб-сервера для зв'язку з програмою. Додавати компоненти проміжного програмного забезпечення між веб-сервером та програмою легко, щоб змінити поведінку вашого запиту / відповіді. Компонент посередництва знаходиться між клієнтом і сервером, обробляючи вхідні запити та вихідні відповіді.

Простіше кажучи, це в основному лише набір вказівок щодо того, як сервер і програма Rails (або будь-який інший веб-додаток Ruby) повинні спілкуватися один з одним .

Щоб використовувати Rack, надайте "додаток": об'єкт, який відповідає методу виклику, приймаючи хеш середовища в якості параметра і повертаючи масив з трьома елементами:

  • Код відповіді HTTP
  • Хеш-заголовки
  • Орган відповіді , який повинен відповісти на кожен запит .

Для отримання додаткового пояснення ви можете перейти за посиланнями нижче.

1. https://rack.github.io/
2. https://redpanthers.co/rack-middleware/
3. https://blog.engineyard.com/2015/understanding-rack-apps-and-middleware
4. https://guides.rubyonrails.org/rails_on_rack.html#resources

У рейках у нас є config.ru як файл стійки, ви можете запустити будь-який файл стійки з rackupкомандою. І типовим портом для цього є 9292. Щоб перевірити це, ви можете просто запустити rackupу свій каталог рейок і побачити результат. Ви також можете призначити порт, на якому ви хочете його запустити. Команда для запуску файлу стійки на будь-якому конкретному порті є

rackup -p PORT_NUMBER

1

зображення, що показує стійку між єдинорогом і рейками

Rack - це дорогоцінний камінь, який забезпечує простий інтерфейс для абстрактного запиту / відповіді HTTP. Rack знаходиться між веб-рамками (Rails, Sinatra тощо) та веб-серверами (єдиноріг, puma) як адаптер. Зверху зображення зберігає сервер єдинорога повністю незалежно від знань про рейки, а рейки не знають про єдиноріг. Це хороший приклад нещільного з’єднання , розділення проблем .

Зображення вгорі - це конференція, присвячена конференції на рейці https://youtu.be/3PnUV9QzB0g, я рекомендую переглянути її для глибшого розуміння.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.