модуль ActionController::Streaming
Потоковая передача данных в Action Controller
Позволяет передавать представления клиенту по мере их рендеринга.
По умолчанию Rails рендерит представления, сначала рендеринга шаблона, а затем макета. Ответ отправляется клиенту после рендеринга всего шаблона, выполнения всех запросов и обработки макета.
Потоковая передача изменяет порядок рендеринга, сначала рендеринга макета, а затем каждой части макета по мере их обработки. Это позволяет быстро передать заголовок HTML (который обычно находится в макете) клиенту, что позволяет загружать JavaScripts и стили раньше, чем обычно.
Некоторые промежуточные ПО Rack могут не работать, и вам нужно быть осторожным при потоковой передаче. Более подробная информация об этом приведена ниже, см. раздел Промежуточное ПО в Streaming.
Потоковую передачу можно легко добавить в шаблон, для этого необходимо передать параметр :stream в render
class PostsController
def index
@posts = Post.all
render stream: true
end
end
Когда использовать потоковую передачу
Потоковая передача может быть излишней для лёгких действий, таких как new или edit. Реальная польза потоковой передачи проявляется при ресурсоёмких действиях, которые, например, выполняют множество запросов к базе данных.
В таких действиях вы хотите отложить выполнение запросов как можно дольше. Например, представьте следующее действие dashboard
def dashboard @posts = Post.all @pages = Page.all @articles = Article.all end
Большинство запросов в данном случае выполняются в контроллере. Для получения выгоды от потоковой передачи вам следует переписать его следующим образом:
def dashboard # Allow lazy execution of the queries @posts = Post.all @pages = Page.all @articles = Article.all render stream: true end
Обратите внимание, что :stream работает только с шаблонами. Рендеринг :json или :xml с :stream не сработает.
Взаимодействие между макетом и шаблоном
При потоковой передаче рендеринг происходит сверху вниз, а не изнутри наружу. Rails начинает с макета, а шаблон рендерится позже, когда достигается его yield.
Это означает, что если ваше приложение в настоящее время полагается на переменные экземпляра, установленные в шаблоне, которые используются в макете, они не будут работать после перехода на потоковую передачу. Правильный способ взаимодействия между макетом и шаблоном, независимо от того, используете ли вы потоковую передачу или нет, заключается в использовании content_for, provide, и yield
Рассмотрим простой пример, где макет ожидает, что шаблон сообщит, какой заголовок использовать:
<html> <head><title><%= yield :title %></title></head> <body><%= yield %></body> </html>
В шаблоне вы будете использовать content_for для указания заголовка:
<%= content_for :title, "Main" %> Hello
И конечным результатом будет:
<html> <head><title>Main</title></head> <body>Hello</body> </html>
Однако, если content_for вызывается несколько раз, конечный результат будет содержать все вызовы, соединённые вместе. Например, если у нас есть следующий шаблон:
<%= content_for :title, "Main" %> Hello <%= content_for :title, " page" %>
Конечным результатом будет:
<html> <head><title>Main page</title></head> <body>Hello</body> </html>
Это означает, что если у вас yield :title в макете, и вы хотите использовать потоковую передачу, вам нужно будет рендерить весь шаблон (и, в конечном итоге, выполнить все запросы) перед передачей заголовка и всех ресурсов, что сводит на нет цель потоковой передачи. В качестве альтернативы, вы можете использовать помощник provide, который делает то же самое, что и content_for, но сообщает макету прекратить поиск других записей и продолжить рендеринг.
Например, шаблон выше, используя provide будет:
<%= provide :title, "Main" %> Hello <%= content_for :title, " page" %>
Приводя к:
<html> <head><title>Main</title></head> <body>Hello</body> </html>
Таким образом, при потоковой передаче необходимо правильно проверить свои шаблоны и выбрать, когда использовать provide и content_for
См. также ActionView::Helpers::CaptureHelper для получения дополнительной информации.
Заголовки, куки, сессия и всплывающие уведомления
При потоковой передаче HTTP-заголовки отправляются клиенту непосредственно перед рендерингом первой строки. Это означает, что изменение заголовков, куки, сессии или всплывающих уведомлений после начала рендеринга шаблона не будет передано клиенту.
Промежуточное ПО
Промежуточное ПО, которому необходимо манипулировать телом, не будет работать с потоковой передачей. Вам следует отключать это промежуточное ПО при потоковой передаче в режиме разработки или производства. Например, Rack::Bug не будет работать при потоковой передаче, так как ему нужно вставлять содержимое в тело HTML.
Также Rack::Cache не будет работать с потоковой передачей, так как оно ещё не поддерживает потоковую передачу тел. При потоковой передаче Cache-Control автоматически устанавливается в значение «no-cache».
Ошибки
Что касается потоковой передачи, обработка исключений становится немного сложнее. Это происходит потому, что часть шаблона уже была рендерена и передана клиенту, что делает невозможным рендеринг всей страницы с ошибкой.
В настоящее время при возникновении исключения в режиме разработки или производства Rails автоматически передаст клиенту:
"><script>window.location = "/500.html"</script></html>
Первые два символа (">) необходимы в случае возникновения исключения во время рендеринга атрибутов для данного тега. Вы можете проверить истинную причину исключения в своём логгере.
Поддержка веб-серверов
Не все веб-серверы поддерживают потоковую передачу «из коробки». Вам необходимо проверить инструкции для каждого из них.
Unicorn
Unicorn поддерживает потоковую передачу, но требует настройки. Для этого нужно создать конфигурационный файл следующим образом:
# unicorn.config.rb listen 3000, tcp_nopush: false
И использовать его при инициализации:
unicorn_rails --config-file unicorn.config.rb
Вы также можете настроить другие параметры, такие как :tcp_nodelay.
Для получения дополнительной информации, пожалуйста, обратитесь к документации.
Если вы используете Unicorn с NGINX, вам может потребоваться настроить NGINX. Потоковая передача должна работать «из коробки» с Rainbows.
Passenger
Phusion Passenger с NGINX предлагает два механизма потоковой передачи «из коробки».
-
Механизм буферизации ответов NGINX, который зависит от значения параметра
passenger_buffer_response(по умолчанию «выкл.»). -
Система буферизации Passenger, которая всегда включена независимо от значения
passenger_buffer_response.
Когда passenger_buffer_response включено, потоковая передача осуществляется на уровне NGINX, который ожидает, пока приложение закончит отправку ответа клиенту.
Для получения дополнительной информации, пожалуйста, обратитесь к документации.
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.