Объяснение
С версии 4.x Workerman улучшил поддержку HTTP-сервиса. Были введены классы запроса, ответа, сессии, а также SSE. Если вы хотите использовать HTTP-сервис Workerman, настоятельно рекомендуется использовать версию 4.x или более поздние.
Обратите внимание, что ниже приведены примеры использования Workerman версии 4.x, несовместимые с Workerman 3.x.
Примечание
- За исключением ответа в формате chunk или SSE, не допускается многократная отправка ответа в одном запросе, то есть не разрешается многократный вызов
$connection->send()
. - Необходимо вызвать
$connection->send()
один раз для каждого запроса, иначе клиент будет бесконечно ожидать.
Быстрый ответ
Если необходимо изменить HTTP-статусный код (по умолчанию 200), или настроить заголовок, cookie, можно напрямую отправить строку в ответ клиенту.
Пример
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('http://0.0.0.0:8080');
$worker->onMessage = function(TcpConnection $connection, Request $request)
{
// Отправить клиенту сообщение "this is body"
$connection->send("this is body");
};
// Запуск воркера
Worker::runAll();
Изменение статусного кода
Если нужно настроить статусный код, заголовок, cookie, необходимо использовать класс ответа Workerman\Protocols\Http\Response
. Например, в следующем примере при обращении к пути /404
будет возвращен статусный код 404, а в теле ответа будет содержаться текст "
Извините, файл не найден
".Пример
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('http://0.0.0.0:8080');
$worker->onMessage = function(TcpConnection $connection, Request $request)
{
if ($request->path() === '/404') {
$connection->send(new Response(404, [], '<h1>Извините, файл не найден</h1>'));
} else {
$connection->send('this is body');
}
};
// Запуск воркера
Worker::runAll();
После инициализации класса Response
для изменения статусного кода можно использовать следующий метод.
$response = new Response(200);
$response->withStatus(404);
$connection->send($response);
Отправка заголовков
Также для отправки заголовков необходимо использовать класс ответа Workerman\Protocols\Http\Response
.
Пример
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('http://0.0.0.0:8080');
$worker->onMessage = function(TcpConnection $connection, Request $request)
{
$response = new Response(200, [
'Content-Type' => 'text/html',
'X-Header-One' => 'Значение заголовка'
], 'this is body');
$connection->send($response);
};
// Запуск воркера
Worker::runAll();
После инициализации класса Response
для добавления или изменения заголовков можно использовать следующий метод.
$response = new Response(200);
// Добавить или изменить один заголовок
$response->header('Content-Type', 'text/html');
// Добавить или изменить несколько заголовков
$response->withHeaders([
'Content-Type' => 'application/json',
'X-Header-One' => 'Значение заголовка'
]);
$connection->send($response);
Перенаправление
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('http://0.0.0.0:8080');
$worker->onMessage = function(TcpConnection $connection, Request $request)
$worker = new Worker('http://0.0.0.0:8080');
$worker->onMessage = function($connection, $request)
{
$location = '/test_location';
$response = new Response(302, ['Location' => $location]);
$connection->send($response);
};
Worker::runAll();
Отправка cookie
Также для отправки cookie необходимо использовать класс ответа Workerman\Protocols\Http\Response
.
Пример
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('http://0.0.0.0:8080');
$worker->onMessage = function(TcpConnection $connection, Request $request)
{
$response = new Response(200, [], 'this is body');
$response->cookie('name', 'tom');
$connection->send($response);
};
// Запуск воркера
Worker::runAll();
Отправка файла
Также для отправки файлов необходимо использовать класс ответа Workerman\Protocols\Http\Response
.
Для отправки файла используйте следующую конструкцию
$response = (new Response())->withFile($file);
$connection->send($response);
- Workerman поддерживает отправку очень больших файлов
- Для больших файлов (более 2МБ) Workerman не считывает весь файл целиком в память, а вместо этого выбирает правильный момент для поэтапного считывания и отправки файла.
- Workerman оптимизирует скорость отправки файла в зависимости от скорости приема клиентом, обеспечивая максимальную скорость отправки файла при минимальном использовании памяти.
- Передача данных не блокируется и не влияет на обработку других запросов
- При отправке файла автоматически добавляется заголовок
Last-Modified
, чтобы сервер мог в следующий раз определить, отправлять ли ответ 304, сэкономив трафик и повысив производительность. - Отправляемый файл автоматически отправляется с правильным заголовком
Content-Type
для браузера - Если файла не существует, он автоматически отправляется как ответ 404
Пример
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('http://0.0.0.0:8080');
$worker->onMessage = function(TcpConnection $connection, Request $request)
{
$file = '/your/path/of/file';
// Проверка заголовка if-modified-since для определения, менялся ли файл
if (!empty($if_modified_since = $request->header('if-modified-since'))) {
$modified_time = date('D, d M Y H:i:s', filemtime($file)) . ' ' . \date_default_timezone_get();
// Если файл не изменен, возвратить 304
if ($modified_time === $if_modified_since) {
$connection->send(new Response(304));
return;
}
}
// Если файл изменен или заголовок if-modified-since отсутствует, отправить файл
$response = (new Response())->withFile($file);
$connection->send($response);
};
// Запуск воркера
Worker::runAll();
Отправка данных в формате http chunk
- Сначала необходимо отправить ответ
Response
с заголовкомTransfer-Encoding: chunked
клиенту - Далее для отправки дополнительных chunk данных используйте класс
Workerman\Protocols\Http\Chunk
- В конце необходимо отправить пустой chunk, чтобы завершить ответ
Пример
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
use Workerman\Protocols\Http\Chunk;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('http://0.0.0.0:8080');
$worker->onMessage = function(TcpConnection $connection, Request $request)
{
// Сначала отправить ответ с заголовком Transfer-Encoding: chunked
$connection->send(new Response(200, array('Transfer-Encoding' => 'chunked'), 'hello'));
// Далее для отправки дополнительных chunk данных используйте класс Workerman\Protocols\Http\Chunk
$connection->send(new Chunk('Первый сегмент данных'));
$connection->send(new Chunk('Второй сегмент данных'));
$connection->send(new Chunk('Третий сегмент данных'));
// В конце обязательно отправить пустой chunk, чтобы завершить ответ
$connection->send(new Chunk(''));
};
// Запуск воркера
Worker::runAll();