TGViewer
Хэндлим тему | Дерепко Хэндлим тему | Дерепко @handle_topic · 276 subscribers
Post #33 587
SSE или стримы на PHP
#пост

SSE – Server-sent events. Стрим – потоковая передача данных в рамках одной сессии.

SSE – протокол общения сервера и клиента, когда сервер отдает информацию частично, при этом не обрывая и не завершая соединение.

Для простой реализации такого протокола потребуется:

- Добавить в HTTP Headers Content-Type: text/event-stream
- В HTTP Body писать следующее:
- Передача сообщения начинается с data:
- Заканчивается сообщение с \n\n на конце строки
- Таких сообщений может быть неограниченное количество
- Задержка между сообщения может быть любая: секунда, минута, 30 минут, прочее

Рассмотрим несколько примеров с возможностями SSE:

- Так пишутся комментарии, с двоеточием вначале


: comment
: another comment
data: ...


- Кастомное имя события. Если не указать event, то событие будет типа message. В моем примере тип события = question с телом в виде JSON


event: question
data: {"tg_channel":"@handle_topic"}


- Событие с id. Не вижу в этом id какой-то полезности для себя.


data: text message
id: 55


- Длинные строки. Это всё еще одно событие.


data: looooooooooooooooong text
data: looooooooooooooooong text
data: looooooooooooooooong text


- А это уже два разных сообщения:


data: payload1

data: payload2



- Еще можно указать retry в milliseconds. Будет учтено при обрыве соединения и попытке восстановления. Например, 1 секунда (1000 миллисекунд).


data: ok
retry: 1000


Это довольно удобная штука, когда нужно что-то недолго* постримить пользователю:

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

Реализация

Реализовать на чистом PHP довольно просто: посмотреть пример можно здесь.

Однако, мало кто пишет на чистом пхп свои бекенды. Скорее всего на бекенде используется какой-то фреймворк с ответами в виде класса Response. Либо сразу в контроллере, либо под капотом происходит трансформация возвращаемого значения в строковый ответ.

Если разбирать PSR ResponseInterface , то HTTP Body формируется через метод withBody, который принимает объект StreamInterface. Ага, вот и стримы обещанные.

Стримы

Так как задать несколько ответов с задержкой?

Раз уж наш ответ является стримом, то стрим не обязан возвращать все данные “за одно чтение”.

Поэтому можно сделать некий буфер, который будет вычитываться в методе read() . Если данных больше не будет, то достаточно поменять флаг eof и вернуть его в соответствующем методе объекта стрима.

Однако, набирать буффер и потом его сбрасывать может быть чревато разными проблемами:

- Бекенд будет думать, что клиент всё принял и обработал
- Клиент получит часть, что-то сломается, и получить остальную часть он уже не сможет
- Дополнительные затраты на память

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

Ограничения

Разберем еще несколько ограничений SSE:

- Можно стримить только body
- Хедеры нельзя менять после начала стрима
- Кодировка всегда UTF-8

Emitter фреймворка должен уметь в стримы, чтобы не выдать первый результат и закрыть стрим, либо объект стрима должен сам уметь блокироваться и чанковать данные.

Проблемы

- Сложная реализация
- Реализовывать стримминг событий на PHP при помощи SSE еще и в PSR обёртках?
- Проще подключить Mercure и настроить его.
- Протокол – пустышка
- Ни авторизации, ни разделения на каналы, ни бродкастинга
- Всё делать либо в HTTP, либо самому
- По сути в нем можно перегонять лишь текст и всё
- Это как HTTP внутри HTTP. Шутка про монитор в мониторе
- Свободные воркеры
- Свободные воркеры веб-сервера превращаются в зомби за мгновение
- Поэтому таймауты обязательны
- Либо Non-blocking I/O. Кстати, надо бы попробовать.

---

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

MDN Server-sent events
StreamInterface
HTML Standard

@handle_topic
  • 👍 8
  • 🤨 1
More from @handle_topic
  1. Sep 9, 2026Пыхник’26 — целая неделя PHP! С 28 сентября по 2 октября пройдёт Пыхник’26 — онлайн-конфер…
  2. Aug 24, 2026Мой Pull Request в vlucas/dotenv смёржили! Рад ли я? Конечно. Прихнаюсь честно, у меня это…
  3. Aug 5, 2026Jetbrains выделили LSP ядро для Java/Kotlin, так что теперь вся (а вся?) мощщщщь IDEA дост…
  4. Jul 30, 2026Вайбкодеры?
  5. Jul 19, 2026Когда выучил высоконагруженные системы @git_rebase / send memes
  6. Jun 30, 2026Jetbrains Air на Windows! Если вы вдруг разрабатываете на винде (сожалею вам), то можете п…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →