web-dev-qa-db-fra.com

Réutiliser la connexion HTTP authentifiée ou le descripteur cUrl

Nous avons un plugin Wordpress sur mesure, qui ajoute une méta-boîte à la page d'édition. Le plug-in accède aux données à partir d'une API HTTP REST semi-privée.

La connexion est authentifiée (DIGEST) et consultée régulièrement. Chaque personne qui rédige une publication interagit plusieurs fois avec celle-ci (généralement par petites rafales) et il y a plus de 100 de ces personnes. Nous voudrions donc nous assurer que les appels HTTP fonctionnent efficacement. Nous voyons deux problèmes:

  • Aucune preuve d'utilisation de Keep-Alive pour empêcher le socket TCP de s'ouvrir et de se fermer constamment.
  • Chaque demande est faite deux fois pour l'authentification DIGEST. Comme c'est le plugin qui est authentifié (pas l'utilisateur), cela représente plus de 99% de perte. Apache a appelé sa solution pour cette authentification préemptive .

Nous pouvons voir la latence dans la méta-boîte lorsque les utilisateurs interagissent avec elle. Il s'agit donc d'un problème réel.

J'entends dire que certains de ces problèmes peuvent être résolus en réutilisant le descripteur cURL, mais je ne trouve aucun conseil de bonne pratique concernant la mise en œuvre de cela dans un plugin WordPress en particulier. L’un des problèmes que nous avons avec cela est que WordPRess ré-initialise efficacement le plug-in à la demande, à notre connaissance.

4
Simon Gibbs

Du fait des limitations fondamentales de PHP dans un environnement Web (mod_php), il est impossible, du moins dans des limites raisonnables, de résoudre l'un ou l'autre de ces problèmes.

Les variables de classe ne persistent pas entre les requêtes Web. Par conséquent, la partie persistante du problème ne peut pas être résolue car toutes les ressources (par exemple, curl handle, socket tcp) seront détruites à la fin de la requête. La réutilisation du descripteur cUrl semble s’appliquer principalement aux scripts de traitement par lots ou aux rares scripts Web qui doivent accéder à plusieurs URL en une seule fois. Les types d'optimisations de performance considérées comme standard pour les développeurs Java ne sont donc pas disponibles pour les développeurs PHP.

On pourrait essayer d'implémenter l'authentification Digest en collant les valeurs de l'en-tête Authorization dans une session, mais cela n'est pas peu coûteux à implémenter (temps de développement élevé) et pas une chose à laquelle de nombreuses entreprises veulent consacrer du temps. Cela pourrait être un beau projet de 3ème année universitaire par exemple.

Espérons que, à un moment donné, quelqu'un publiera un produit complémentaire pour PHP dans Apache, qui acheminera les demandes HTTP vers un pool de connexions TCP externe au processus. Cela rapporterait probablement de l’argent, étant donné que cela entraînerait beaucoup de latence dans les requêtes HTTP en amont de PHP.

2
Simon Gibbs

Contrôle de la demande cURL

Même si l'inspection et le débogage d'une demande cURL ne sont pas spécifiques à WordPress, vous devez connaître une bonne partie des éléments internes de l'API HTTP WP pour la contourner. Je me suis écrit un plugin pour le faire pour moi, que j'ai modifié/démonté et attaché pour que vous puissiez l'utiliser. Il va afficher les détails de l'objet cURL dans le hook d'arrêt, à la fois dans l'interface utilisateur d'administration et dans le front-end/thème.

Ce que vous pouvez faire, c'est utiliser exactement le même hook http_api_curl et attraper l'objet cURL. Puis enregistrez-le dans une variable de classe, associez-lui vos prochains appels et poursuivez. Je n'ai rien fait de tel moi-même auparavant, mais cela devrait être faisable.

Modifier

Comme le nombre de modifications est limité ici, j'ai déplacé le développement de ce plugin vers mon compte GitHub . Si vous avez des notes, des commentaires ou des suggestions, laissez un commentaire ici.

Le plugin ci-dessous est entièrement fonctionnel. Encore une version beaucoup plus avancée est sur GitHub.

<?php
/** 
 * Plugin Name: (#81791) Dump cURL Request & Response 
 * Author:      Franz Josef Kaiser
 */
add_action( 'plugins_loaded', array( 'WPSE81791_cURL', 'init' ) );
class WPSE81791_cURL
{
    protected static $instance;

    public static $dump;

    public static function init()
    {
        null === self :: $instance AND self :: $instance = new self;
        return self :: $instance;
    }

    public function __construct()
    {
        add_action( 'http_api_curl', array( $this, 'dump_curl' ) );
        add_action( 'shutdown', array( $this, 'do_dump' ) );
    }

    /**
     * Debug the response in the middle.
     * Catches the cURL object during the request.
     * @param  cURL $handle
     * @return void
     */
    public function dump_curl( &$handle )
    {
        curl_setopt( $handle, CURLINFO_HEADER_OUT, 1 );
        curl_setopt( $handle, CURLOPT_HEADER, 0 );
        curl_setopt( $handle, CURLOPT_HEADERFUNCTION, array( $this, 'dump_curl_buffer_cb' ) );
        curl_setopt( $handle, CURLOPT_WRITEFUNCTION, array( $this, 'dump_curl_buffer_cb' ) );
        curl_exec( $handle );
        $this->add_dump(
             curl_getinfo( $handle, CURLINFO_HEADER_OUT )
            .$this->dump_curl_buffer_cb( null )
            .'<br />Nr. of Errors: '.curl_errno( $handle )
            .'<br />Errors: '.curl_error( $handle )
        );
    }

    /**
     * Callback for cURL dump method
     * @param  object $curl
     * @param  null   $data
     * @return int
     */
    public function dump_curl_buffer_cb( $curl, $data = null )
    {
        static $buffer = '';
        if ( is_null( $curl ) )
        {
            $r = $buffer;
            $buffer = '';
            return $r;
        }
        $buffer .= $data;
        return strlen( $data );
    }

    /**
     * Adds data to the static data stack
     * @param  
     * @return void
     */
    public function add_dump( $data )
    {
        self :: $dump[] = $data;
    }

    /**
     * Dumps the data stack for debug
     * @param  
     * @return void
     */
    public function do_dump()
    {
        printf(
             '<pre>%s</pre>'
            ,var_export( implode( "<br />", self :: $dump ), true ) 
        );
    }
}
2
kaiser