Descripción

A partir de la versión 4.x, Workerman ha mejorado el soporte para servicios HTTP. Se han introducido las clases de solicitud, respuesta, sesión y SSE. Si deseas utilizar los servicios HTTP de Workerman, se recomienda encarecidamente usar Workerman 4.x o versiones posteriores.

Nota: lo que sigue son usos de Workerman 4.x, no son compatibles con Workerman 3.x.

Aviso

  • A menos que se envíe una respuesta en fragmentos o una respuesta SSE, no se permite enviar múltiples respuestas en una sola solicitud, es decir, no se permite llamar a $connection->send() múltiples veces en una sola solicitud.
  • Cada solicitud necesita que se llame a $connection->send() al menos una vez para enviar la respuesta, de lo contrario, el cliente se quedará esperando.

Respuesta rápida

Cuando no es necesario cambiar el código de estado HTTP (predeterminado 200), o personalizar cabeceras o cookies, puedes enviar una cadena directamente al cliente para completar la respuesta.

Ejemplo

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)
{
    // Directamente enviar esto es el cuerpo al cliente
    $connection->send("this is body");
};

// Ejecutar worker
Worker::runAll();

Cambiar código de estado

Cuando es necesario personalizar el código de estado, cabeceras o cookies, es necesario usar la clase de respuesta Workerman\Protocols\Http\Response. Por ejemplo, el siguiente ejemplo devuelve un código de estado 404 cuando la ruta de acceso es /404, con un contenido de cuerpo de <h1>Lo sentimos, el archivo no existe</h1>.

Ejemplo

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>Lo sentimos, el archivo no existe</h1>'));
    } else {
        $connection->send('this is body');
    }
};

// Ejecutar worker
Worker::runAll();

Cuando la clase Response ya ha sido inicializada, para cambiar el código de estado usa el siguiente método.

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

Enviar cabeceras

De igual manera, para enviar cabeceras es necesario usar la clase de respuesta Workerman\Protocols\Http\Response.

Ejemplo

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

// Ejecutar worker
Worker::runAll();

Cuando la clase Response ya ha sido inicializada, para agregar o cambiar cabeceras usa el siguiente método.

$response = new Response(200);
// Agregar o cambiar una cabecera
$response->header('Content-Type', 'text/html');
// Agregar o cambiar múltiples cabeceras
$response->withHeaders([
    'Content-Type' => 'application/json',
    'X-Header-One' => 'Header Value'
]);
$connection->send($response);

Redirección

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

Enviar cookies

De igual manera, para enviar cookies es necesario usar la clase de respuesta Workerman\Protocols\Http\Response.

Ejemplo

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

// Ejecutar worker
Worker::runAll();

Enviar archivos

De igual manera, para enviar archivos es necesario usar la clase de respuesta Workerman\Protocols\Http\Response.

Al enviar archivos, usa el siguiente método.

$response = (new Response())->withFile($file);
$connection->send($response);
  • Workerman admite el envío de archivos muy grandes.
  • Para archivos grandes (más de 2M), Workerman no leerá todo el archivo en la memoria de una vez, sino que leerá el archivo en fragmentos y lo enviará en el momento adecuado.
  • Workerman optimizará la velocidad de lectura y envío del archivo según la velocidad de recepción del cliente, asegurando el envío más rápido posible del archivo mientras reduce al mínimo el uso de memoria.
  • El envío de datos es no bloqueante y no afectará el procesamiento de otras solicitudes.
  • Al enviar un archivo, se añadirá automáticamente la cabecera Last-Modified, para que el servidor puede determinar si enviar una respuesta 304 en la próxima solicitud para ahorrar en la transferencia de archivos y mejorar el rendimiento.
  • El archivo enviado se enviará con la cabecera Content-Type adecuada al navegador.
  • Si el archivo no existe, se convertirá automáticamente a una respuesta 404.

Ejemplo

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 la cabecera if-modified-since para determinar si el archivo ha sido 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();
        // Si el archivo no ha sido modificado, devolver 304
        if ($modified_time === $if_modified_since) {
            $connection->send(new Response(304));
            return;
        }
    }
    // Si el archivo ha sido modificado o no hay cabecera if-modified-since, entonces enviar el archivo
    $response = (new Response())->withFile($file);
    $connection->send($response);
};

// Ejecutar worker
Worker::runAll();

Enviar datos en chunks HTTP

  • Primero debes enviar una respuesta que incluya la cabecera Transfer-Encoding: chunked al cliente.
  • Para enviar los datos en chunks posteriores, utiliza la clase Workerman\Protocols\Http\Chunk.
  • Finalmente, debes enviar un chunk vacío para finalizar la respuesta.

Ejemplo

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)
{
    // Primero enviar una respuesta con la cabecera Transfer-Encoding: chunked
    $connection->send(new Response(200, array('Transfer-Encoding' => 'chunked'), 'hello'));
    // Los datos en chunk posteriores enviados con la clase Workerman\Protocols\Http\Chunk
    $connection->send(new Chunk('Primer fragmento de datos'));
    $connection->send(new Chunk('Segundo fragmento de datos'));
    $connection->send(new Chunk('Tercer fragmento de datos'));
    // Finalmente, se debe enviar un chunk vacío para acabar la respuesta
    $connection->send(new Chunk(''));
};

// Ejecutar worker
Worker::runAll();