Что такое промежуточное ПО Rack?

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

Ответ 1

Стойка как дизайн

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

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

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

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

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

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

  • Декорирование: как улучшить запрос, чтобы улучшить последующую обработку?

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

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

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

сообщество

Также вокруг Rack Middleware развивается отличная экосистема - вы сможете найти готовые компоненты стойки для выполнения всех вышеперечисленных шагов и многого другого. Посмотрите Rack GitHub wiki для получения списка промежуточного программного обеспечения.

Какое промежуточное ПО?

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

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

Ответ 2

Прежде всего, Rack - это ровно две вещи:

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

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

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

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

Как указано в соглашении, наш сервер имеет метод, называемый вызовом, который принимает хеш среды и возвращает массив с формой [status, headers, body] для обслуживающего веб-сервера. Попробуйте это, просто позвонив в rawn. Сервер, совместимый с стойкой по умолчанию, может быть, 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 и voila:

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

Middleware

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

Скажем, мы хотим добавить журнал на наш 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   

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

Стойка - драгоценный камень

Хотя стойка - в первую очередь - это конвенция, она также является камнем, который обеспечивает отличную функциональность. Один из них мы уже использовали для нашего сервера JSON, команды rawn. Но там еще! Драгоценный камень в стойке обеспечивает небольшие приложения для множества случаев использования, например, для статических файлов или целых каталогов. Посмотрим, как мы обслуживаем простой файл, например, очень простой 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 (в форме истории) здесь, в моем блоге: http://gauravchande.com/what-is-rack-in-ruby-rails

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

Ответ 4

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

Ответ 5

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

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

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

Ответ 7

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

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

С помощью Rack вы можете написать приложение для стойки.

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

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

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

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

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

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

  • gem install rack
  • Создайте файл config.ru - стойка знает, что нужно искать.

Мы создадим крошечное приложение Rack, которое возвращает Response (экземпляр Rack::Response), который Response Body - это массив, содержащий строку String: "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, и вы увидите "Hello, World!". оказаны.

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

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

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

Как бы то ни было, то, что вы написали здесь, - это приложение Rack!

Создание приложения стойки взаимодействует с хешем входящей среды

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

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

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

Из документов стойки в среде Hash: "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 в нашу кодовую базу - класс: MessageSetter,
  • хеш среды будет сначала попадать в этот класс и будет передан как параметр: env,
  • MessageSetter будет вставлять ключ 'MESSAGE' в хэш env, его значение 'Hello, World!', если env['QUERY_STRING'] пусто; env['QUERY_STRING'] если нет,
  • наконец, он вернет @app.call(env) - @app следующее приложение в "Stack": 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 docs мы видим, что Rack::Builder реализует небольшую DSL для итеративного построения приложений Rack. Это в основном означает, что вы можете создать "Stack", состоящий из одного или нескольких Middlewares и приложения "нижнего уровня" для отправки. Все запросы, поступающие на ваше приложение нижнего уровня, будут сначала обработаны вашим промежуточным программным обеспечением.

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

Средство промежуточного уровня должно:

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

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

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

(перед тем, как продолжить движение),

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

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

Выводы

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

Вы можете построить "конвейер запросов", состоящий из нескольких Middlewares, которые имеют дело с такими вещами, как:

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

(над пунктами пули от другого ответа на эту тему)

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

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

Ответ 8

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 команды rackup. И порт по умолчанию для этого 9292. Чтобы проверить это, вы можете просто запустить rackup в вашей директории rails и посмотреть результат. Вы также можете назначить порт, на котором вы хотите его запустить. Команда для запуска файла стойки на любом конкретном порту

rackup -p PORT_NUMBER