Описание

С версии 4.x Workerman усилил поддержку HTTP-сервисов. Были добавлены классы запроса, ответа, сессии и SSE. Если вы хотите использовать HTTP-сервис Workerman, настоятельно рекомендуется использовать версию Workerman 4.x или более новые версии.

Обратите внимание, что все примеры относятся к версии Workerman 4.x и не совместимы с версией Workerman 3.x.

Примечание

  • Если не отправляется chunk или SSE-ответ, то не разрешается многократная отправка ответа в одном запросе, то есть в одном запросе нельзя многократно вызывать $connection->send().
  • Каждый запрос должен завершаться вызовом $connection->send() для отправки ответа, иначе клиент будет продолжать ожидать.

Быстрый ответ

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

Пример

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
Worker::runAll();

Изменение кода состояния

Когда нужно настроить код состояния, заголовки, куки, необходимо использовать класс ответа Workerman\Protocols\Http\Response. Например, в приведенном ниже примере при доступе по пути /404 возвращается код состояния 404 с содержимым <h1>Извините, файл не существует</h1>.

Пример

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
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
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)
{
    $location = '/test_location';
    $response = new Response(302, ['Location' => $location]);
    $connection->send($response);
};
Worker::runAll();

Отправка куки

Аналогично, для отправки куки необходимо использовать класс ответа 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
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
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)
{
    // Сначала отправляем Response с заголовком 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
Worker::runAll();