Descrição

O Workerman a partir da versão 4.x reforçou o suporte ao serviço HTTP. Introduziu classes de requisição, classe de resposta, classe de sessão e SSE. Se você deseja utilizar o serviço HTTP do Workerman, é altamente recomendado usar a versão 4.x ou uma versão superior.

Observe que todos os exemplos a seguir são para a versão 4.x do Workerman, não são compatíveis com a versão 3.x.

Atenção

  • A menos que a resposta seja um chunk ou uma resposta SSE, não é permitido enviar múltiplas respostas em uma única requisição, ou seja, não é permitido chamar $connection->send() várias vezes em uma única requisição.
  • Cada requisição deve finalizar chamando $connection->send() para enviar uma resposta, caso contrário, o cliente ficará esperando indefinidamente.

Resposta rápida

Quando não é necessário alterar o código de status HTTP (padrão 200), ou personalizar headers ou cookies, você pode simplesmente enviar uma string diretamente para o cliente para completar a resposta.

Exemplo

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)
{
    // Enviar diretamente "this is body" para o cliente
    $connection->send("this is body");
};

// Executar o worker
Worker::runAll();

Alterar código de status

Quando é necessário personalizar o código de status, headers ou cookies, você deve usar a classe de resposta Workerman\Protocols\Http\Response. Por exemplo, o exemplo abaixo retorna um código 404 quando o caminho acessado é /404, com o corpo da resposta como <h1>Desculpe, arquivo não encontrado</h1>.

Exemplo

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>Desculpe, arquivo não encontrado</h1>'));
    } else {
        $connection->send('this is body');
    }
};

// Executar o worker
Worker::runAll();

Quando a classe Response já estiver inicializada, você pode alterar o código de status usando o método abaixo.

$response = new Response(200);
$response->withStatus(404);
$connection->send($response);

Enviar headers

Da mesma forma, para enviar headers, você precisa usar a classe de resposta Workerman\Protocols\Http\Response.

Exemplo

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' => 'Header Value'
    ], 'this is body');
    $connection->send($response);
};

// Executar o worker
Worker::runAll();

Quando a classe Response já estiver inicializada, você pode adicionar ou alterar headers usando o método abaixo.

$response = new Response(200);
// Adicionar ou alterar um header
$response->header('Content-Type', 'text/html');
// Adicionar ou alterar múltiplos headers
$response->withHeaders([
    'Content-Type' => 'application/json',
    'X-Header-One' => 'Header Value'
]);
$connection->send($response);

Redirecionamento

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);
};

// Executar o worker
Worker::runAll();

Enviar cookies

Da mesma forma, para enviar cookies, você precisa usar a classe de resposta Workerman\Protocols\Http\Response.

Exemplo

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);
};

// Executar o worker
Worker::runAll();

Enviar arquivos

Da mesma forma, para enviar arquivos, você precisa usar a classe de resposta Workerman\Protocols\Http\Response.

Para enviar um arquivo, use a seguinte abordagem:

$response = (new Response())->withFile($file);
$connection->send($response);
  • O Workerman suporta o envio de arquivos muito grandes.
  • Para arquivos grandes (maiores que 2M), o Workerman não carrega o arquivo inteiro na memória de uma vez, mas lê e envia o arquivo em partes no momento adequado.
  • O Workerman otimiza a velocidade de leitura e envio de arquivos com base na velocidade de recebimento do cliente, garantindo o envio mais rápido possível do arquivo enquanto reduz ao mínimo o uso da memória.
  • O envio de dados é não bloqueante e não afeta o processamento de outras requisições.
  • Ao enviar arquivos, o cabeçalho Last-Modified será automaticamente adicionado, para que em solicitações futuras o servidor possa determinar se deve enviar uma resposta 304 para economizar na transferência de arquivos e melhorar o desempenho.
  • Os arquivos enviados automaticamente usarão o cabeçalho Content-Type apropriado ao serem enviados para o navegador.
  • Se o arquivo não existir, será automaticamente convertido para uma resposta 404.

Exemplo

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';
    // Verificar o cabeçalho if-modified-since para determinar se o arquivo foi modificado
    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();
        // Se o arquivo não foi modificado, retorna 304
        if ($modified_time === $if_modified_since) {
            $connection->send(new Response(304));
            return;
        }
    }
    // Se o arquivo foi modificado ou não há cabeçalho if-modified-since, envia o arquivo
    $response = (new Response())->withFile($file);
    $connection->send($response);
};

// Executar o worker
Worker::runAll();

Enviar dados HTTP chunk

  • Primeiro, deve-se enviar uma resposta que contenha o cabeçalho Transfer-Encoding: chunked para o cliente.
  • Os dados chunk subsequentes são enviados usando a classe Workerman\Protocols\Http\Chunk.
  • Finalmente, deve-se enviar um chunk vazio para encerrar a resposta.

Exemplo

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)
{
    // Primeiro, envia uma resposta com o cabeçalho Transfer-Encoding: chunked
    $connection->send(new Response(200, array('Transfer-Encoding' => 'chunked'), 'hello'));
    // Os dados Chunk subsequentes são enviados com a classe Workerman\Protocols\Http\Chunk
    $connection->send(new Chunk('Primeiro pedaço de dados'));
    $connection->send(new Chunk('Segundo pedaço de dados'));
    $connection->send(new Chunk('Terceiro pedaço de dados'));
    // Finalmente, é necessário enviar um chunk vazio para encerrar a resposta
    $connection->send(new Chunk(''));
};

// Executar o worker
Worker::runAll();