Antwort

Die Antwort ist tatsächlich ein support\Response-Objekt. Um dieses Objekt einfach zu erstellen, bietet Webman einige Hilfsfunktionen an.

Gibt eine beliebige Antwort zurück

Beispiel

<?php
namespace app\controller;

use support\Request;

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

Die response-Funktion ist wie folgt implementiert:

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

Sie können auch zunächst ein leeres response-Objekt erstellen und dann an geeigneten Stellen mit $response->cookie(), $response->header(), $response->withHeaders() und $response->withBody() die Rückgabedaten festlegen.

public function hello(Request $request)
{
    // Erstellen eines Objekts
    $response = response();

    // .... Geschäftslogik weggelassen

    // Cookie setzen
    $response->cookie('foo', 'value');

    // .... Geschäftslogik weggelassen

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

    // .... Geschäftslogik weggelassen

    // Die zurückzugebenden Daten festlegen
    $response->withBody('返回的数据');
    return $response;
}

Gibt JSON zurück

Beispiel

<?php
namespace app\controller;

use support\Request;

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

Die json-Funktion ist wie folgt implementiert:

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

Gibt XML zurück

Beispiel

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

Die xml-Funktion ist wie folgt implementiert:

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

Gibt eine Ansicht zurück

Erstellen Sie die Datei app/controller/FooController.php wie folgt:

<?php
namespace app\controller;

use support\Request;

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

Erstellen Sie die Datei app/view/foo/hello.html wie folgt:

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

Umleitung

<?php
namespace app\controller;

use support\Request;

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

Die redirect-Funktion ist wie folgt implementiert:

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

Header-Einstellungen

<?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' 
        ]);
    }
}

Es ist auch möglich, die Methoden header und withHeaders zu verwenden, um Header einzeln oder in einer Gruppe festzulegen.

<?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',
        ]);
    }
}

Sie können auch die Header zuerst festlegen und dann zuletzt die zurückzugebenden Daten festlegen.

public function hello(Request $request)
{
    // Erstellen eines Objekts
    $response = response();

    // .... Geschäftslogik weggelassen

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

    // .... Geschäftslogik weggelassen

    // Die zurückzugebenden Daten festlegen
    $response->withBody('返回的数据');
    return $response;
}

Cookie setzen

<?php
namespace app\controller;

use support\Request;

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

Sie können auch die Cookies zuerst setzen und dann zuletzt die zurückzugebenden Daten festlegen.

public function hello(Request $request)
{
    // Erstellen eines Objekts
    $response = response();

    // .... Geschäftslogik weggelassen

    // Cookie setzen
    $response->cookie('foo', 'value');

    // .... Geschäftslogik weggelassen

    // Die zurückzugebenden Daten festlegen
    $response->withBody('返回的数据');
    return $response;
}

Die vollständigen Parameter der cookie-Methode sind wie folgt:

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

Gibt eine Datei zurück

<?php
namespace app\controller;

use support\Request;

class FooController
{
    public function hello(Request $request)
    {
        return response()->file(public_path() . '/favicon.ico');
    }
}
  • Webman unterstützt das Senden von sehr großen Dateien.
  • Für große Dateien (über 2 MB) wird Webman die gesamte Datei nicht auf einmal in den Speicher laden, sondern die Datei in passenden Zeitabständen lesen und senden.
  • Webman optimiert die Datei-Lese- und -Sende-Geschwindigkeit basierend auf der Empfangsgeschwindigkeit des Clients, um die Datei so schnell wie möglich zu senden und gleichzeitig die Speichernutzung auf das Minimum zu reduzieren.
  • Der Datentransfer ist nicht blockierend und beeinträchtigt die Verarbeitung anderer Anfragen nicht.
  • Die file-Methode fügt automatisch den if-modified-since-Header hinzu und überprüft beim nächsten Anfrage den if-modified-since-Header. Wenn die Datei nicht geändert wurde, wird direkt ein 304 zurückgegeben, um Bandbreite zu sparen.
  • Die gesendete Datei wird automatisch mit dem entsprechenden Content-Type-Header an den Browser gesendet.
  • Wenn die Datei nicht existiert, wird automatisch eine 404-Antwort zurückgegeben.

Datei herunterladen

<?php
namespace app\controller;

use support\Request;

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

Die download-Methode ist im Wesentlichen mit der file-Methode identisch, der Unterschied ist

  1. Wenn der Dateiname festgelegt ist, wird die Datei heruntergeladen und nicht im Browser angezeigt.
  2. Die download-Methode überprüft den if-modified-since-Header nicht.

Ausgabe erfassen

Einige Bibliotheken drucken den Inhalt direkt auf die Standardausgabe, d.h. die Daten werden im Terminal angezeigt und nicht an den Browser gesendet. In diesem Fall müssen wir ob_start(); und ob_get_clean(); verwenden, um die Daten in einer Variablen zu erfassen und dann die Daten an den Browser zu senden, wie zum Beispiel:

<?php

namespace app\controller;

use support\Request;

class ImageController
{
    public function get(Request $request)
    {
        // Bild erstellen
        $im = imagecreatetruecolor(120, 20);
        $text_color = imagecolorallocate($im, 233, 14, 91);
        imagestring($im, 1, 5, 5,  'A Simple Text String', $text_color);

        // Ausgabe erfassen
        ob_start();
        // Bild ausgeben
        imagejpeg($im);
        // Bildinhalt abrufen
        $image = ob_get_clean();

        // Bild senden
        return response($image)->header('Content-Type', 'image/jpeg');
    }
}

Chunk-Antworten

Manchmal möchten wir die Antwort chunkweise senden. Siehe das folgende Beispiel.

<?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
    {
        // Verbindung abrufen
        $connection = $request->connection;
        // HTTP-Paketinhalt zeitgesteuert senden
        $timer = Timer::add(1, function () use ($connection, &$timer) {
            static $i = 0;
            if ($i++ < 10) {
                // HTTP-Paketinhalt senden
                $connection->send(new Chunk($i));
            } else {
                // Unnötigen Timer entfernen, um Speicherlecks zu vermeiden
                Timer::del($timer);
                // Leeres Chunk-Paket senden, um dem Client das Ende der Antwort mitzuteilen
                $connection->send(new Chunk(''));
            }
        });
        // Zuerst einen HTTP-Header mit "Transfer-Encoding: chunked" ausgeben, der HTTP-Paketinhalt wird asynchron gesendet
        return response()->withHeaders([
            "Transfer-Encoding" => "chunked",
        ]);
    }

}

Wenn Sie ein großes Modell aufrufen, siehe das folgende Beispiel.

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, falls der Zugriff nicht möglich ist, kann die Adresse https://api.openai-proxy.com verwendet werden
        $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) {
                // Wenn das OpenAI-Interface Daten zurückgibt, an den Browser weiterleiten
                $connection->send(new Chunk(json_encode($data, JSON_UNESCAPED_UNICODE) . "\n"));
            },
            'complete' => function($result, $response) use ($connection) {
                // Am Ende der Antwort überprüfen, ob es Fehler gibt
                if (isset($result['error'])) {
                    $connection->send(new Chunk(json_encode($result, JSON_UNESCAPED_UNICODE) . "\n"));
                }
                // Ein leeres Chunk zurückgeben, um das Ende der Antwort anzuzeigen
                $connection->send(new Chunk(''));
            },
        ]);
        // Zuerst einen HTTP-Header zurückgeben, die restlichen Daten werden asynchron zurückgegeben
        return response()->withHeaders([
            "Transfer-Encoding" => "chunked",
        ]);
    }
}