workerman/http-client

Description

workerman/http-client est un composant client HTTP asynchrone. Toutes les réponses aux requêtes sont asynchrones et non-bloquantes, avec une piscine de connexions intégrée et des requêtes et réponses conformes à la norme PSR7.

Installation :

composer require workerman/http-client

Exemples :

Utilisation des requêtes get et post

use Workerman\Worker;

require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker();
$worker->onWorkerStart = function () {
    $http = new Workerman\Http\Client();

    $http->get('https://example.com/', function ($response) {
        var_dump($response->getStatusCode());
        echo $response->getBody();
    }, function ($exception) {
        echo $exception;
    });

    $http->post('https://example.com/', ['key1' => 'value1', 'key2' => 'value2'], function ($response) {
        var_dump($response->getStatusCode());
        echo $response->getBody();
    }, function ($exception) {
        echo $exception;
    });

    $http->request('https://example.com/', [
        'method' => 'POST',
        'version' => '1.1',
        'headers' => ['Connection' => 'keep-alive'],
        'data' => ['key1' => 'value1', 'key2' => 'value2'],
        'success' => function ($response) {
            echo $response->getBody();
        },
        'error' => function ($exception) {
            echo $exception;
        }
    ]);
};
Worker::runAll();

Téléchargement de fichiers

<?php
use Workerman\Worker;

require_once 'vendor/autoload.php';

$worker = new Worker();
$worker->onWorkerStart = function () {
    $http = new Workerman\Http\Client();
    // télécharger un fichier
    $multipart = new \Workerman\Psr7\MultipartStream([
        [
            'name' => 'file',
            'contents' => fopen(__FILE__, 'r')
        ],
        [
            'name' => 'json',
            'contents' => json_encode(['a'=>1, 'b'=>2])
        ]
    ]);
    $boundary = $multipart->getBoundary();
    $http->request('http://127.0.0.1:8787', [
        'method' => 'POST',
        'version' => '1.1',
        'headers' => ['Connection' => 'keep-alive', 'Content-Type' => "multipart/form-data; boundary=$boundary"],
        'data' => $multipart,
        'success' => function ($response) {
            echo $response->getBody();
        },
        'error' => function ($exception) {
            echo $exception;
        }
    ]);
};

Worker::runAll();

Retour en streaming avec progress

<?php
require_once __DIR__ . '/vendor/autoload.php';

use Workerman\Connection\TcpConnection;
use Workerman\Http\Client;
use Workerman\Protocols\Http\Chunk;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
use Workerman\Worker;

$worker = new Worker('http://0.0.0.0:1234');
$worker->onMessage = function (TcpConnection $connection, Request $request) {
    $http = new Client();
    $http->request('https://api.ai.com/v1/chat/completions', [
        'method' => 'POST',
        'data' => json_encode([
            'model' => 'gpt-3.5-turbo',
            'temperature' => 1,
            'stream' => true,
            'messages' => [['role' => 'user', 'content' => 'hello']],
        ]),
        'headers' => [
            'Content-Type' => 'application/json',
            'Authorization' => 'Bearer sk-xxx',
        ],
        'progress' => function($buffer) use ($connection) {
            $connection->send(new Chunk($buffer));
        },
        'success' => function($response) use ($connection) {
            $connection->send(new Chunk('')); // envoyer un chunk vide pour indiquer la fin de la réponse
        },
    ]);
    $connection->send(new Response(200, [
        //"Content-Type" => "application/octet-stream",
        "Transfer-Encoding" => "chunked",
    ], ''));
};
Worker::runAll();

Options

<?php
require __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
$worker = new Worker();
$worker->onWorkerStart = function(){
    $options = [
        'max_conn_per_addr' => 128, // le nombre maximal de connexions simultanées par domaine
        'keepalive_timeout' => 15,  // temps d'inactivité avant fermeture de la connexion
        'connect_timeout'   => 30,  // temps d'attente pour la connexion
        'timeout'           => 30,  // temps d'attente pour une réponse après la requête
    ];
    $http = new Workerman\Http\Client($options);

    $http->get('http://example.com/', function($response){
        var_dump($response->getStatusCode());
        echo $response->getBody();
    }, function($exception){
        echo $exception;
    });
};
Worker::runAll();

Utilisation des coroutines

Attention
L'utilisation des coroutines nécessite workerman>=5.1, http-client>=3.0, et l'installation de l'extension swoole ou swow, ou installer composer require revolt/event-loop pour prendre en charge le moteur Fiber.

use Workerman\Worker;

require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker();
$worker->eventLoop = \Workerman\Events\Swoole::class; // Ou \Workerman\Events\Swow::class ou \Workerman\Events\Fiber::class
$worker->onWorkerStart = function () {
    $http = new Workerman\Http\Client();

    $response = $http->get('https://example.com/');
    var_dump($response->getStatusCode());
    echo $response->getBody();

    $response = $http->post('https://example.com/', ['key1' => 'value1', 'key2' => 'value2']);
    var_dump($response->getStatusCode());
    echo $response->getBody();

    $response = $http->request('https://example.com/', [
        'method' => 'POST',
        'version' => '1.1',
        'headers' => ['Connection' => 'keep-alive'],
        'data' => ['key1' => 'value1', 'key2' => 'value2'],
    ]);
    echo $response->getBody();
};
Worker::runAll();

Lorsque aucune fonction de rappel n'est définie, le client renvoie les résultats de la requête asynchrone de manière synchrone, le processus de demande ne bloque pas le processus en cours, permettant ainsi de traiter les requêtes de manière concurrente.

Remarques :

  1. Le projet doit d'abord charger require __DIR__ . '/vendor/autoload.php';

  2. Tout le code asynchrone doit s'exécuter après le démarrage de workerman.

  3. Prend en charge tous les projets développés sur la base de workerman, y compris Webman, GatewayWorker, PHPSocket.io, etc.

  4. Essayez de conserver l'objet client pour réutilisation, ce qui permet de tirer pleinement parti de la piscine de connexions pour améliorer les performances, n'instanciez pas new Workerman\Http\Client() à chaque fois.

Utilisation dans webman

Si vous avez besoin d'utiliser des requêtes HTTP asynchrones dans webman et de renvoyer les résultats au frontend, consultez l'exemple suivant :

<?php
namespace app\controller;

use support\Request;
use support\Response;
use Workerman\Protocols\Http\Chunk;

class IndexController
{
    public function index(Request $request)
    {
        // Conserver l'objet client pour réutilisation peut améliorer considérablement la performance
        static $http;
        $connection = $request->connection;
        $http = $http ?: new \Workerman\Http\Client();
        $http->get('https://example.com/', function ($response) use ($connection) {
            $connection->send(new Chunk($response->getBody()));
            $connection->send(new Chunk('')); // envoyer un chunk vide pour indiquer la fin de la réponse
        });
        return response()->withHeaders([
            "Transfer-Encoding" => "chunked",
        ]);
    }
}

L'exemple ci-dessus renvoie d'abord un en-tête HTTP avec chunked au client, puis envoie les données au client sous forme de chunks, vous pouvez également consulter l'utilisation des coroutines ci-dessus.

Attention
Le code ci-dessus stocke l'objet client dans une variable statique de méthode pour permettre la réutilisation, il peut également être stocké dans un membre statique de classe ou dans un objet global.

Demande de l'interface OpenAI en webman et retour en streaming

Référez-vous à https://www.workerman.net/plugin/157