web-dev-qa-db-fra.com

Comment nourrir un EventSource HTML5 avec un REST Point de terminaison personnalisé de l'API?

Donc, dans cette quête pour créer un pseudo service de discussion Web personnalisé avec Telegram, j'essaie de récupérer les messages que Telegram envoie au serveur et de les rediriger vers le frontend. SSE avec HTML5 EventSource semble être la solution la plus simple et la plus simple pour ce faire.

Le fait est que EventSource a besoin que les en-têtes 'Content-Type: text/event-stream' et 'Cache-Control: no-cache' soient définis dans la réponse du serveur.

Si un WP_REST_REQUEST est renvoyé sur la fonction qui définit la réponse ("set_telegram_response", ci-dessous), rien n'arrivera à EventSource. Mais si la réponse est renvoyée, EventSource fermera la connexion en affirmant que le serveur envoie une réponse JSON au lieu d'une réponse text/event-stream.

Voici les principes de base de la classe que j'ai écrite pour cela. Si je tire une requête GET sur ce noeud final, la chaîne "Some text" sera renvoyée. Mais le script EventSource n’imprime rien, comme si la réponse était vide.

class Chat
{
    private static $token, $telegram, $chat_id;
    public $telegram_message;

    public function __construct()
    {
        self::$chat_id = "<TELEGRAM-CHAT-ID>";
        self::$token = "<TELEGRAM-TOKEN>";
        self::$telegram = "https://api.telegram.org:443/bot" . self::$token;

        add_action('rest_api_init', array( $this, 'set_telegram_message_endpoint' ));
        add_action('admin_post_chat_form', array( $this, 'chat_telegram' ));
        add_action('admin_post_nopriv_chat_form', array( $this, 'chat_telegram' ));
    }

    public function set_telegram_message_endpoint()
    {
        register_rest_route('mybot/v2', 'bot', array(
            array(
                'methods' => WP_REST_SERVER::CREATABLE,
                'callback' => array( $this, 'get_telegram_message' ),
            ),
            array(
                'methods' => WP_REST_SERVER::READABLE,
                'callback' => array( $this, 'set_telegram_message' ),
            ),
        ));
    }

    public function set_telegram_message( WP_REST_REQUEST $request )
    {
        $new_response = new WP_REST_Response( "Some text" . PHP_EOL . PHP_EOL, 200 );
        $new_response->header( 'Content-Type', 'text/event-stream' );
        $new_response->header( 'Cache-Control', 'no-cache' );
        ob_flush();
        return $new_response;
    }

    public function get_telegram_message( WP_REST_REQUEST $request )
    {
        $this->telegram_message = $request;
        //return rest_ensure_response( $request['message']['text'] );
    }

    public function chat_telegram( $input = null )
    {
        $mensaje = $input === '' ? $_POST['texto'] : $input;
        echo $mensaje;

        $query = http_build_query([
            'chat_id' => self::$chat_id,
            'text' => $mensaje,
            'parse_mode' => "Markdown",
        ]);

        $response = file_get_contents( self::$telegram . '/sendMessage?' . $query );
        return $response;
    }
}

J'ai passé toute l'après-midi et une partie de la matinée à lire la documentation sur REST API, mais je n'ai trouvé aucun indice sur ce qui pourrait ne pas être correct ou sur la façon de le faire.

BTW, le serveur sur lequel je déploie cela peut gérer les requêtes EventSource - je viens de l'essayer sur un script de test PHP et tout a bien fonctionné. Donc, je ne sais vraiment pas ce qui se passe ici. Toute aide serait extrêmement appréciée.

4
acidrums4

Cela est dû au fait que l'API restante utilise en interne json_encode() pour générer les données. Il existe deux manières de résoudre ce problème.

1. Empêcher l'API d'envoyer les données

Cela peut paraître un peu étrange et soulever quelques problèmes, mais vous pouvez définir le type d’en-tête et faire écho au contenu avant de renvoyer les données:

header( 'Content-Type: text/event-stream' );
header( 'Cache-Control: no-cache' );

// Echo whatever data you got here

// Prevent the API from continuing
exit();

Comme ce n’est pas la méthode standard d’utilisation de l’API, certains problèmes peuvent survenir. Je n'ai pas essayé moi-même.

2. Utilisez admin-ajax.php

Au lieu de l'API de repos, utilisez l'administrateur AJAX. La mise en œuvre est la même. En gros, si vous utilisez json_encode() aux côtés de die();, vous obtiendrez les mêmes résultats que l'API rest. La page de codex } sur ce sujet couvre presque tout. En utilisant admin AJAX, vous pouvez contrôler entièrement les en-têtes et le type de sortie.

2
Jack Johansson

Je ne suis pas en mesure de tester cela, mais pouvez-vous essayer de modifier les en-têtes de réponse à l'aide de ce crochet:

add_action( 'rest_api_init', function() {

    remove_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );

    add_filter( 'rest_pre_serve_request', function( $value ) {

        header( 'Content-Type', 'text/event-stream' );
        header( 'Cache-Control', 'no-cache' );

        return $value;

    });
}, 15 );

J'ai eu l'idée de ici .

0
dboris