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-Typeadecuada 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: chunkedal 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();