Risposta

La risposta è in realtà un oggetto support\Response. Per facilitare la creazione di questo oggetto, Webman fornisce alcune funzioni helper.

Restituisce una risposta qualsiasi

Esempio

<?php
namespace app\controller;

use support\Request;

class FooController
{
    public function hello(Request $request)
    {
        return response('hello webman');
    }
}

La funzione response è implementata come segue:

function response($body = '', $status = 200, $headers = array())
{
    return new Response($status, $headers, $body);
}

Puoi anche creare un oggetto response vuoto e poi utilizzare $response->cookie() $response->header() $response->withHeaders() $response->withBody() per impostare il contenuto di ritorno nei luoghi appropriati.

public function hello(Request $request)
{
    // Creare un oggetto
    $response = response();

    // .... Logica aziendale omessa

    // Impostare il cookie
    $response->cookie('foo', 'value');

    // .... Logica aziendale omessa

    // Impostare l'intestazione http
    $response->header('Content-Type', 'application/json');
    $response->withHeaders([
                'X-Header-One' => 'Header Value 1',
                'X-Header-Tow' => 'Header Value 2',
            ]);

    // .... Logica aziendale omessa

    // Impostare i dati da restituire
    $response->withBody('Dati restituiti');
    return $response;
}

Restituisce json

Esempio

<?php
namespace app\controller;

use support\Request;

class FooController
{
    public function hello(Request $request)
    {
        return json(['code' => 0, 'msg' => 'ok']);
    }
}

La funzione json è implementata come segue

function json($data, $options = JSON_UNESCAPED_UNICODE)
{
    return new Response(200, ['Content-Type' => 'application/json'], json_encode($data, $options));
}

Restituisce xml

Esempio

<?php
namespace app\controller;

use support\Request;

class FooController
{
    public function hello(Request $request)
    {
        $xml = <<<XML
               <?xml version='1.0' standalone='yes'?>
               <values>
                   <truevalue>1</truevalue>
                   <falsevalue>0</falsevalue>
               </values>
               XML;
        return xml($xml);
    }
}

La funzione xml è implementata come segue:

function xml($xml)
{
    if ($xml instanceof SimpleXMLElement) {
        $xml = $xml->asXML();
    }
    return new Response(200, ['Content-Type' => 'text/xml'], $xml);
}

Restituisce una vista

Crea un file app/controller/FooController.php come segue

<?php
namespace app\controller;

use support\Request;

class FooController
{
    public function hello(Request $request)
    {
        return view('foo/hello', ['name' => 'webman']);
    }
}

Crea un file app/view/foo/hello.html come segue

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>webman</title>
</head>
<body>
hello <?=htmlspecialchars($name)?>
</body>
</html>

Reindirizzamento

<?php
namespace app\controller;

use support\Request;

class FooController
{
    public function hello(Request $request)
    {
        return redirect('/user');
    }
}

La funzione redirect è implementata come segue:

function redirect($location, $status = 302, $headers = [])
{
    $response = new Response($status, ['Location' => $location]);
    if (!empty($headers)) {
        $response->withHeaders($headers);
    }
    return $response;
}

Impostazione intestazioni

<?php
namespace app\controller;

use support\Request;

class FooController
{
    public function hello(Request $request)
    {
        return response('hello webman', 200, [
            'Content-Type' => 'application/json',
            'X-Header-One' => 'Header Value' 
        ]);
    }
}

Puoi anche utilizzare i metodi header e withHeaders per impostare singolarmente o in massa le intestazioni.

<?php
namespace app\controller;

use support\Request;

class FooController
{
    public function hello(Request $request)
    {
        return response('hello webman')
        ->header('Content-Type', 'application/json')
        ->withHeaders([
            'X-Header-One' => 'Header Value 1',
            'X-Header-Tow' => 'Header Value 2',
        ]);
    }
}

Puoi anche impostare le intestazioni in anticipo, poi impostare i dati da restituire alla fine.

public function hello(Request $request)
{
    // Creare un oggetto
    $response = response();

    // .... Logica aziendale omessa

    // Impostare l'intestazione http
    $response->header('Content-Type', 'application/json');
    $response->withHeaders([
                'X-Header-One' => 'Header Value 1',
                'X-Header-Tow' => 'Header Value 2',
            ]);

    // .... Logica aziendale omessa

    // Impostare i dati da restituire
    $response->withBody('Dati restituiti');
    return $response;
}

Impostare cookie

<?php
namespace app\controller;

use support\Request;

class FooController
{
    public function hello(Request $request)
    {
        return response('hello webman')
        ->cookie('foo', 'value');
    }
}

Puoi anche impostare i cookie in anticipo e poi impostare i dati da restituire alla fine.

public function hello(Request $request)
{
    // Creare un oggetto
    $response = response();

    // .... Logica aziendale omessa

    // Impostare il cookie
    $response->cookie('foo', 'value');

    // .... Logica aziendale omessa

    // Impostare i dati da restituire
    $response->withBody('Dati restituiti');
    return $response;
}

I parametri completi del metodo cookie sono:

cookie($name, $value = '', $max_age = 0, $path = '', $domain = '', $secure = false, $http_only = false)

Restituisce un flusso di file

<?php
namespace app\controller;

use support\Request;

class FooController
{
    public function hello(Request $request)
    {
        return response()->file(public_path() . '/favicon.ico');
    }
}
  • Webman supporta l'invio di file di grandi dimensioni
  • Per file di grandi dimensioni (superiori a 2M), Webman non carica l'intero file in memoria in una sola volta, ma legge e invia il file a pezzi nel momento opportuno
  • Webman ottimizza la velocità di lettura e invio del file in base alla velocità di ricezione del client, garantendo la massima velocità di invio del file mantenendo al minimo l'uso della memoria
  • L'invio dei dati è non bloccante e non influisce sul trattamento di altre richieste
  • Il metodo file aggiungerà automaticamente l'intestazione if-modified-since e nella richiesta successiva controlla l'intestazione if-modified-since. Se il file non è stato modificato, verrà restituito direttamente il 304 per risparmiare larghezza di banda
  • I file inviati verranno automaticamente inviati al browser con la corretta intestazione Content-Type
  • Se il file non esiste, verrà automaticamente convertito in una risposta 404

Scarica file

<?php
namespace app\controller;

use support\Request;

class FooController
{
    public function hello(Request $request)
    {
        return response()->download(public_path() . '/favicon.ico', 'file_name.ico');
    }
}

Il metodo download è sostanzialmente simile al metodo file, con la differenza che:

  1. Impostando il nome del file scaricato, il file verrà scaricato e non visualizzato nel browser
  2. Il metodo download non controllerà l'intestazione if-modified-since

Ottieni output

Al alcune librerie stampano direttamente il contenuto del file sull'output standard, quindi i dati verranno stampati nel terminale della riga di comando e non verranno inviati al browser. In questo caso, dobbiamo catturare i dati in una variabile utilizzando ob_start(); ob_get_clean(); e poi inviarli al browser, ad esempio:

<?php

namespace app\controller;

use support\Request;

class ImageController
{
    public function get(Request $request)
    {
        // Creare un'immagine
        $im = imagecreatetruecolor(120, 20);
        $text_color = imagecolorallocate($im, 233, 14, 91);
        imagestring($im, 1, 5, 5,  'Una semplice stringa di testo', $text_color);

        // Iniziare a catturare l'output
        ob_start();
        // Uscita dell'immagine
        imagejpeg($im);
        // Ottenere il contenuto dell'immagine
        $image = ob_get_clean();

        // Inviare l'immagine
        return response($image)->header('Content-Type', 'image/jpeg');
    }
}

Risposta a pezzi

A volte vogliamo inviare una risposta a pezzi, puoi fare riferimento al seguente esempio.

<?php

namespace app\controller;

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

class IndexController
{
    public function index(Request $request): Response
    {
        // Ottenere la connessione
        $connection = $request->connection;
        // Inviare pacchetti http a intervalli regolari
        $timer = Timer::add(1, function () use ($connection, &$timer) {
            static $i = 0;
            if ($i++ < 10) {
                // Inviare il pacchetto http
                $connection->send(new Chunk($i));
            } else {
                // Rimuovere il timer non più necessario, evitando una fuga di memoria
                Timer::del($timer);
                // Inviare un pacchetto Chunk vuoto per notificare al client che la risposta è finita
                $connection->send(new Chunk(''));
            }
        });
        // Inviare prima un'intestazione http con Transfer-Encoding: chunked, il corpo http verrà inviato in modo asincrono
        return response()->withHeaders([
            "Transfer-Encoding" => "chunked",
        ]);
    }

}

Se stai chiamando un modello di intelligenza artificiale, puoi fare riferimento al seguente esempio.

composer require webman/openai
<?php
namespace app\controller;
use support\Request;

use Webman\Openai\Chat;
use Workerman\Protocols\Http\Chunk;

class ChatController
{
    public function completions(Request $request)
    {
        $connection = $request->connection;
        // https://api.openai.com usa https://api.openai-proxy.com se non è accessibile in Cina
        $chat = new Chat(['apikey' => 'sk-xx', 'api' => 'https://api.openai.com']);
        $chat->completions(
            [
                'model' => 'gpt-3.5-turbo',
                'stream' => true,
                'messages' => [['role' => 'user', 'content' => 'hello']],
            ], [
            'stream' => function($data) use ($connection) {
                // Quando l'API OpenAI restituisce i dati, inoltrali al browser
                $connection->send(new Chunk(json_encode($data, JSON_UNESCAPED_UNICODE) . "\n"));
            },
            'complete' => function($result, $response) use ($connection) {
                // Controlla se ci sono errori alla fine della risposta
                if (isset($result['error'])) {
                    $connection->send(new Chunk(json_encode($result, JSON_UNESCAPED_UNICODE) . "\n"));
                }
                // Restituisce un chunk vuoto per rappresentare la fine della risposta
                $connection->send(new Chunk(''));
            },
        ]);
        // Restituisci prima un'intestazione http, i dati successivi verranno restituiti in modo asincrono
        return response()->withHeaders([
            "Transfer-Encoding" => "chunked",
        ]);
    }
}