web-dev-qa-db-fra.com

Comment activer la connexion filaire pour un trafic Java HttpURLConnection?

J'ai utilisé Jakarta commons HttpClient dans un autre projet et je voudrais le même fil logging output mais en utilisant le "standard" HttpUrlConnection.

J'ai utilisé Fiddler comme proxy mais je voudrais enregistrer le trafic directement à partir de Java.

Capturer ce qui se passe dans les flux d'entrée et de sortie de la connexion n'est pas suffisant, car les en-têtes HTTP sont écrits et utilisés par la classe HttpUrlConnection. Par conséquent, je ne pourrai pas les enregistrer.

38
Serxipc

J'ai pu enregistrer tout le trafic SSL mettant en œuvre mon propre SSLSocketFactory par-dessus celui par défaut. 

Cela a fonctionné pour moi car toutes nos connexions utilisent HTTPS et nous pouvons définir la fabrique de socket avec la méthode HttpsURLConnection.setSSLSocketocket

Vous trouverez une solution plus complète permettant de surveiller tous les sockets à l'adresse suivante: http://www.javaspecialists.eu/archive/Issue169.html Merci à Lawrence Dol d'avoir été dans la bonne direction. d'utiliser Socket.setSocketImplFactory

Voici mon pas prêt pour le code de production:

public class WireLogSSLSocketFactory extends SSLSocketFactory {

    private SSLSocketFactory delegate;

    public WireLogSSLSocketFactory(SSLSocketFactory sf0) {
        this.delegate = sf0;
    }

    public Socket createSocket(Socket s, String Host, int port,
            boolean autoClose) throws IOException {
        return new WireLogSocket((SSLSocket) delegate.createSocket(s, Host, port, autoClose));
    }

    /*
    ...
    */

    private static class WireLogSocket extends SSLSocket {

        private SSLSocket delegate;

        public WireLogSocket(SSLSocket s) {
            this.delegate = s;
        }

        public OutputStream getOutputStream() throws IOException {
            return new LoggingOutputStream(delegate.getOutputStream());
        }

        /*
        ...
        */

        private static class LoggingOutputStream extends FilterOutputStream {
            private static final Logger logger = Logger.getLogger(WireLogSocket.LoggingOutputStream.class);
            //I'm using a fixed charset because my app always uses the same. 
            private static final String CHARSET = "ISO-8859-1";
            private StringBuffer sb = new StringBuffer();

            public LoggingOutputStream(OutputStream out) {
                super(out);
            }

            public void write(byte[] b, int off, int len)
                    throws IOException {
                sb.append(new String(b, off, len, CHARSET));
                logger.info("\n" + sb.toString());
                out.write(b, off, len);
            }

            public void write(int b) throws IOException {
                sb.append(b);
                logger.info("\n" + sb.toString());
                out.write(b);
            }

            public void close() throws IOException {
                logger.info("\n" + sb.toString());
                super.close();
            }
        }
    }
}
14
Serxipc

Selon la source HttpURLConnection de Sun , il existe un support de journalisation via JUL .

Configuration (ajustez le chemin si nécessaire):

-Djava.util.logging.config.file=/full/path/to/logging.properties

logging.properties:

handlers= Java.util.logging.ConsoleHandler
Java.util.logging.ConsoleHandler.level = FINEST
Sun.net.www.protocol.http.HttpURLConnection.level=ALL

Cela se connectera à la console, ajustez au besoin pour, par exemple, se connecter à un fichier. 

Exemple de sortie:

2010-08-07 00:00:31 Sun.net.www.protocol.http.HttpURLConnection writeRequests
FIN: Sun.net.www.MessageHeader@16caf435 pairs: {GET /howto.html HTTP/1.1: null}{User-Agent: Java/1.6.0_20}{Host: www.rgagnon.com}{Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2}{Connection: keep-alive}
2010-08-07 00:00:31 Sun.net.www.protocol.http.HttpURLConnection getInputStream
FIN: Sun.net.www.MessageHeader@5ac0728 pairs: {null: HTTP/1.1 200 OK}{Date: Sat, 07 Aug 2010 04:00:33 GMT}{Server: Apache}{Accept-Ranges: bytes}{Content-Length: 17912}{Keep-Alive: timeout=5, max=64}{Connection: Keep-Alive}{Content-Type: text/html}

Notez que cela n'imprime que les en-têtes sans corps.

Voir http://www.rgagnon.com/javadetails/Java-debug-HttpURLConnection-problem.html pour des détails.

Il existe également la propriété système -Djavax.net.debug=all. Mais c'est surtout utile pour le débogage SSL .

43
Vadzim

Solution n ° 1: Utiliser un motif de décorateur

Vous devrez utiliser motif Decorator sur la classe { HttpURLConnection } _ pour étendre ses fonctionnalités. Puis substituez toutes les méthodes HttpURLConnection et déléguez l'opération au pointeur Component, capturez également les informations requises et enregistrez-les.

Assurez-vous également que vous substituez la classe parente URLConnection.getOutputStream () }: OutputStream et URLConnection.html # getInputStream () }: InputStream retourne les objets OutputStream _ et InputStream décorés.

.

Solution n ° 2: Utiliser un proxy http personnalisé en mémoire

Ecrivez un serveur proxy http simple et faites-le démarrer dans son thread séparé lors du démarrage et de l'initialisation de l'application. Voir Exemple de serveur proxy simple .

Avoir votre application configurée pour utiliser utiliser le proxy HTTP ci-dessus pour toutes vos demandes. Voir configuration de Java pour utiliser les mandataires .

Désormais, tout votre trafic passe au-dessus du proxy, comme ce qui se passe dans Fiddler. Par conséquent, vous avez accès au flux http brut "de client à serveur" et "de serveur à client". Vous devrez interpréter ces informations brutes et les consigner au besoin.

Update: Utilisez le proxy HTTP comme adaptateur pour le serveur Web basé sur SSL.

  == Client System =============================== 
  |                                              | 
  |    ------------------------------            | 
  |   |                              |           | 
  |   |    Java process              |           | 
  |   |                       ----   |           | 
  |   |        ----------    |    |  |           | 
  |   |       |          |    -O  |  |           | 
  |   |       |  Logging |        |  |           | 
  |   |       |   Proxy <---HTTP--   |    -----  | 
  |   |       |  Adapter |           |   |     | | 
  |   |       |  Thread o------------------>   | | 
  |   |       |        o |           |   |     | | 
  |   |        --------|-            |   | Log | | 
  |   |                |             |    -----  | 
  |    ----------------|-------------            | 
  |                    |                         | 
  =====================|========================== 
                       |                           
                       |                           
                     HTTPS                         
                      SSL                          
                       |                           
  == Server System ====|========================== 
  |                    |                         | 
  |    ----------------|----------------         | 
  |   |                V                |        | 
  |   |                                 |        | 
  |   |   Web Server                    |        | 
  |   |                                 |        | 
  |    ---------------------------------         | 
  |                                              | 
  ================================================ 
9
Gladwin Burboz

Sous Linux, vous pouvez exécuter le VM sous strace:

strace -o strace.out -s 4096 -e trace = réseau -f Java ...

3
weberjn

Je ne pense pas que vous puissiez le faire automatiquement, mais vous pouvez sous-classe FilterOutputStream et FilterInputStream avec les flux de sortie et d'entrée de HttpUrlConnection en tant que paramètres. Ensuite, lorsque les octets sont écrits/lus, enregistrez-les et transmettez-les aux flux sous-jacents.

2
Adam Batkin

Si vous êtes seulement intéressé par le contenu affiché sur le fil (en-têtes, corps, etc.), vous voudrez peut-être essayer wireshark a.

Cela présente l'avantage de ne pas avoir à changer de code, bien que si vous souhaitez activer la journalisation via le code, cette réponse ne s'applique pas.

2
beny23

Pourquoi ne pas utiliser AspectJ pour insérer un pointcut afin d’ajouter des conseils de journalisation autour d’une méthode? Je pense qu'AspectJ peut se faufiler dans des méthodes privées/protégées.

Il semble que Sun.net.www.protocol.http.HttpURLConnection.writeRequest puisse appeler Sun.net.www.http.HttpClient.writeRequest qui prend l’objet MessageHeader en tant qu’entrée afin que ce soit votre cible.

En fin de compte, cela pourrait fonctionner, mais sera terriblement fragile et ne fonctionnera que sur la machine virtuelle Sun. et en réalité, vous ne pouviez avoir confiance qu'en la version exacte que vous utilisez.

2
danpaq

Pour actualiser avec l'environnement Java 8:

Après @sleske répondre

System.setProperty("javax.net.debug","all");

travaillé pour moi hors de la boîte. 

La suggestion de @weberjn était également 

strace -o strace.out -s 4096 -e trace=network -f Java

mais pas utile si le trafic avec le trafic SSL est traité car il vide le flux encodé.

Tous les autres tours de code ne fonctionnaient pas pour moi, mais peut-être que je n'essayais pas assez fort.

0
Lukasz Bulak