Что такое промежуточное программное обеспечение для стойки? - PullRequest
255 голосов
/ 13 февраля 2010

Что такое промежуточное программное обеспечение Rack в Ruby? Я не смог найти хорошего объяснения того, что они подразумевают под «промежуточным ПО».

Ответы [ 8 ]

332 голосов
/ 13 февраля 2010

Rack as Design

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

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

Например, для Rack I могут быть отдельные этапыконвейер делает:

  • Аутентификация : когда запрос поступает, правильны ли данные для входа в систему?Как проверить эту OAuth, базовую аутентификацию HTTP, имя / пароль?

  • Авторизация : «авторизован ли пользователь для выполнения этой конкретной задачи?», То есть рольна основе безопасности.

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

  • Декорация : как улучшить запрос для улучшения обработки в нисходящем направлении?

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

  • Выполнение : фактически обработать запрос и предоставить ответ.

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

Сообщество

Существует также великолепная экосистема, развивающаяся вокруг Rack Middleware - вы должны найти-строенные компоненты стойки, чтобы сделать все шаги вышебуду больше.См. Rack GitHub wiki для списка промежуточного программного обеспечения .

Что такое промежуточное программное обеспечение?

Промежуточное программное обеспечение - это ужасный термин, который относится к любому программному компоненту / библиотеке, который помогает, нонепосредственно не участвует в выполнении какой-либо задачи.Очень распространенными примерами являются регистрация, аутентификация и другие общие компоненты горизонтальной обработки .Это, как правило, вещи, которые нужны всем в нескольких приложениях, но не слишком много людей заинтересованы (или должны быть) в создании самих себя.

Дополнительная информация

  • Комментарий о способе фильтрации запросов, вероятно, содержится в эпизоде ​​ RailsCast 151: Rack Middleware приведение экрана.

  • Промежуточное программное обеспечение стойки развилось из Rack, и в представлено отличное введение Введение в промежуточное ПО Rack *1076*.

  • Есть введениек промежуточному программному обеспечению в Википедии здесь .

70 голосов
/ 21 февраля 2012

Прежде всего, стойка это ровно две вещи:

  • Соглашение об интерфейсе веб-сервера
  • Драгоценный камень

Стойка - интерфейс веб-сервера

Сама основа стойки - это простое соглашение. Каждый совместимый с стойкой веб-сервер всегда будет вызывать метод вызова для объекта, который вы ему предоставите, и обрабатывать результат этого метода. Rack точно определяет, как должен выглядеть этот метод вызова и что он должен возвращать. Это стойка.

Давайте попробуем. Я буду использовать WEBrick в качестве стоечного веб-сервера, но подойдет любой из них. Давайте создадим простое веб-приложение, которое возвращает строку JSON. Для этого мы создадим файл с именем config.ru. Config.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, который принимает хеш среды и возвращает массив с формой [status, headers, body] для обслуживания веб-сервером. Давайте попробуем это, просто позвонив в rackup. Сервер, совместимый со стойкой по умолчанию, может быть, 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. В какой-то момент они реализуют метод вызова, прорабатывают весь код платформы и, наконец, возвращают ответ в типичной форме [status, headers, body].

Например, в 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, если какой-либо маршрут совпадает. Если это так, он передает хэш env приложению для вычисления ответа, в противном случае он немедленно отвечает 404. Таким образом, любой веб-сервер, совместимый с соглашением об интерфейсе стойки, может обслуживать полностью запущенное приложение Rails.

Middleware

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 автоматически вызывает метод call в промежуточном программном обеспечении и ожидает обратно массив [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   

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

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

Хотя стойка, прежде всего, является соглашением, она также является жемчужиной, которая обеспечивает отличную функциональность. Один из них мы уже использовали для нашего JSON-сервера, команда rackup. Но это еще не все! Стойка Gem предоставляет небольшие приложения для множества случаев использования, таких как обслуживание статических файлов или даже целых каталогов. Давайте посмотрим, как мы обслуживаем простой файл, например очень простой 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, которые вы можете включить прямо сейчас из любого места.

20 голосов
/ 17 октября 2013

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

Обратная связь приветствуется.

6 голосов
/ 11 марта 2016

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

6 голосов

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.

4 голосов
/ 12 февраля 2017

Что такое стойка?

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

Используя Rack, вы можете написать приложение Rack.

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

Что такое приложение для установки в стойку?

Чтобы использовать Rack, вы должны предоставить «приложение» - объект, который отвечает на метод #call с хэшом среды в качестве параметра (обычно определяется как env). #call должен возвращать массив из трех значений:

  • Код состояния (например, «200»),
  • a Хеш заголовков ,
  • Тело ответа (которое должно отвечать методу Ruby, each).

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

Очень простое приложение для стойки:

  • Создайте файл config.ru - Rack знает, как искать это.

Мы создадим крошечное приложение Rack, которое возвращает ответ (экземпляр Rack::Response), чье тело ответа представляет собой массив, содержащий строку: "Hello, World!".

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

При посещении соответствующего порта в нашем браузере мы увидим «Hello, World!» отображается в окне просмотра.

#./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 , и вы должны увидеть «Hello, World!» оказаны.

Это не исчерпывающее объяснение, но, по сути, здесь происходит то, что Клиент (браузер) отправляет HTTP-запрос Rack через ваш локальный сервер, а Rack создает экземпляр MessageApp и запускает call, передавая Хэш среды как параметр метода (аргумент env).

Rack принимает возвращаемое значение (массив) и использует его для создания экземпляра Rack::Response и отправляет его обратно клиенту. Браузер использует magic для печати «Hello, World!» на экран.

Кстати, если вы хотите посмотреть, как выглядит хеш среды, просто поставьте puts env под def call(env).

Как минимум, то, что вы написали здесь, является приложением Rack!

Взаимодействие стоечного приложения с хэшем Incoming Environment

В нашем маленьком приложении Rack мы можем взаимодействовать с хешем env (см. здесь для получения дополнительной информации о хэше Environment).

Мы реализуем возможность для пользователя вводить свою собственную строку запроса в URL, следовательно, эта строка будет присутствовать в HTTP-запросе, инкапсулируясь в качестве значения в одну из пар ключ / значение хэша Environment.

Наше приложение Rack получит доступ к этой строке запроса из хэша Environment и отправит ее обратно клиенту (в нашем случае, нашему браузеру) через тело в ответе.

Из стойки документов по хешу окружающей среды: "QUERY_STRING: часть URL запроса, которая следует за?, Если есть. Может быть пустой, но всегда обязательна!"

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

Теперь, rackup и зайдите localhost:9292?hello (?hello - строка запроса), и вы должны увидеть 'hello' в окне просмотра.

Промежуточное программное обеспечение для стойки

Мы будем:

  • вставьте часть 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. В основном это означает, что вы можете создать «стек», состоящий из одного или нескольких промежуточных программ и приложения «нижнего уровня» для отправки. Все запросы, поступающие в ваше приложение нижнего уровня, будут сначала обрабатываться вашим Middleware (s).

#use указывает промежуточное программное обеспечение для использования в стеке. В качестве аргумента используется промежуточное программное обеспечение.

Промежуточное программное обеспечение стойки должно:

  • имеет конструктор, который принимает следующее приложение в стеке в качестве параметра.
  • отвечает на метод call, который принимает хэш Environment в качестве параметра.

В нашем случае «Middleware» - это MessageSetter, «конструктором» является метод initialize MessageSetter, «следующим приложением» в стеке является MessageApp.

Итак, из-за того, что Rack::Builder делает под капотом, аргумент app метода MessageSetter initialize - MessageApp.

(обдумайте вышесказанное, прежде чем двигаться дальше)

Таким образом, каждый компонент Middleware, по сути, «передает» существующий хэш среды следующему приложению в цепочке, поэтому у вас есть возможность изменить этот хэш среды в Middleware, прежде чем передать его следующему приложению в стеке. .

#run принимает аргумент, который является объектом, который отвечает на #call и возвращает Ответ стойки (экземпляр Rack::Response).

Выводы

Используя Rack::Builder, вы можете создавать цепочки промежуточного программного обеспечения, и любой запрос к вашему приложению будет обрабатываться каждым промежуточным программным обеспечением по очереди, прежде чем окончательно обрабатывается последней частью стека (в нашем случае, MessageApp). Это чрезвычайно полезно, поскольку разделяет различные этапы обработки запросов. С точки зрения «разделения интересов», это не может быть намного чище!

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

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

(выше пул из другого ответа в этой теме)

Вы часто будете видеть это в профессиональных приложениях Синатры. Синатра использует 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

Полезные ссылки

4 голосов
/ 12 ноября 2013

Я использовал промежуточное ПО Rack для решения пары проблем:

  1. Перехват ошибок синтаксического анализа JSON с помощью пользовательского промежуточного программного обеспечения Rack и возврат красиво отформатированных сообщений об ошибках при отправке клиентом JSON
  2. Сжатие содержимого с помощью Rack :: Deflater

Это дало довольно элегантные исправления в обоих случаях.

0 голосов
/ 04 апреля 2019

Rack - Интерфейс ч / б Web & App Server

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

В rails у нас config.ru в виде файла стойки, вы можете запустить любой файл стойки командой rackup. И порт по умолчанию для этого 9292. Чтобы проверить это, вы можете просто запустить rackup в вашей директории rails и посмотреть результат. Вы также можете назначить порт, на котором вы хотите его запустить. Команда для запуска файла стойки на любом конкретном порту:

rackup -p PORT_NUMBER
...