Как включить протоколирование проводов для трафика Java HttpURLConnection? - PullRequest
39 голосов
/ 18 сентября 2009

Я использовал Jakarta commons HttpClient в другом проекте, и я хотел бы получить такой же вывод wire logging , но с использованием "стандартного" HttpUrlConnection.

Я использовал Fiddler в качестве прокси, но я бы хотел регистрировать трафик непосредственно из Java.

Захват потоков входного и выходного соединения недостаточен, поскольку заголовки HTTP записываются и используются классом HttpUrlConnection, поэтому я не смогу регистрировать заголовки.

Ответы [ 8 ]

44 голосов
/ 09 сентября 2012

Согласно источнику связи HttpURLC от Sun имеется некоторая поддержка регистрации через JUL .

Настройка (отрегулируйте путь по мере необходимости):

-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

Это позволит войти в консоль, настроить, как требуется, например, войти в файл.

Пример вывода:

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}

Обратите внимание, что при этом печатаются только заголовки без тела.

Подробнее см. http://www.rgagnon.com/javadetails/java-debug-HttpURLConnection-problem.html.

Существует также системное свойство -Djavax.net.debug=all. Но это в основном полезно для отладки SSL .

15 голосов
/ 16 февраля 2010

Мне удалось зарегистрировать весь трафик SSL, используя мой собственный SSLSocketFactory поверх стандартного.

Это сработало для меня, потому что все наши соединения используют HTTPS, и мы можем установить фабрику сокетов методом HttpsURLConnection.setSSLSocketFactory .

Более полное решение, позволяющее осуществлять мониторинг всех сокетов, можно найти по адресу http://www.javaspecialists.eu/archive/Issue169.html Спасибо Lawrence Dol за указание в правильном направлении использования Socket.setSocketImplFactory

Вот мой не готовый к производству код:

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();
            }
        }
    }
}
9 голосов
/ 18 февраля 2010

Решение № 1: Использовать шаблон декоратора

Вам нужно будет использовать Шаблон декоратора в HttpURLConnection класс, чтобы расширить его функциональность. Затем переопределите все методы HttpURLConnection и делегируйте операцию указателю компонента, а также соберите необходимую информацию и зарегистрируйте ее.

Также убедитесь, что вы переопределите родительский класс URLConnection.getOutputStream () : OutputStream и URLConnection.html # getInputStream () : InputStream методы возврата декорированных OutputStream и InputStream объектов.

.

Решение № 2: Использовать пользовательский http-прокси в памяти

Напишите простой http прокси-сервер и запустите его в отдельном потоке во время запуска и инициализации приложения. См. Пример простого прокси-сервера .

Настройте ваше приложение на , используйте прокси HTTP выше для всех ваших запросов. См. Настройка Java для использования прокси .

Теперь весь ваш трафик проходит через прокси, как и в fiddler. Следовательно, у вас есть доступ к необработанному http-потоку «от клиента к серверу», а также «обратно с сервера на клиент». Вам придется интерпретировать эту необработанную информацию и регистрировать ее по мере необходимости.

Обновление: Использовать HTTP-прокси в качестве адаптера для веб-сервера на основе SSL.

  == Client System =============================== 
  |                                              | 
  |    ------------------------------            | 
  |   |                              |           | 
  |   |    Java process              |           | 
  |   |                       ----   |           | 
  |   |        ----------    |    |  |           | 
  |   |       |          |    -O  |  |           | 
  |   |       |  Logging |        |  |           | 
  |   |       |   Proxy <---HTTP--   |    -----  | 
  |   |       |  Adapter |           |   |     | | 
  |   |       |  Thread o------------------>   | | 
  |   |       |        o |           |   |     | | 
  |   |        --------|-            |   | Log | | 
  |   |                |             |    -----  | 
  |    ----------------|-------------            | 
  |                    |                         | 
  =====================|========================== 
                       |                           
                       |                           
                     HTTPS                         
                      SSL                          
                       |                           
  == Server System ====|========================== 
  |                    |                         | 
  |    ----------------|----------------         | 
  |   |                V                |        | 
  |   |                                 |        | 
  |   |   Web Server                    |        | 
  |   |                                 |        | 
  |    ---------------------------------         | 
  |                                              | 
  ================================================ 
3 голосов
/ 30 декабря 2015

В Linux вы можете запустить виртуальную машину под strace:

strace -o strace.out -s 4096 -e трассировка = сеть -f java ...

2 голосов
/ 23 февраля 2010

Если вы заинтересованы только в том, чтобы получить информацию о проводном соединении (заголовки, текст и т. Д.), Вы можете попробовать wireshark .

Преимуществом этого является отсутствие необходимости изменять какой-либо код, хотя, если вы включили регистрацию с помощью кода, это то, что вам нужно, этот ответ неприменим.

2 голосов
/ 19 февраля 2010

А как насчет использования AspectJ для вставки Pointcut для добавления рекомендаций по ведению журнала для метода? Я считаю, что AspectJ может проложить себе путь к закрытым / защищенным методам.

Похоже, что sun.net.www.protocol.http.HttpURLConnection.writeRequest может вызывать sun.net.www.http.HttpClient.writeRequest, который принимает объект MessageHeader в качестве входных данных, чтобы он стал вашей целью.

В конце концов, это может сработать, но будет ужасно хрупким и работать только на Sun JVM; и действительно, вы можете доверять только той версии, которую используете.

2 голосов
/ 18 сентября 2009

Я не думаю, что вы можете сделать это автоматически, но вы можете создать подкласс FilterOutputStream и FilterInputStream с потоками вывода и ввода HttpUrlConnection в качестве параметров. Затем, когда байты записываются / читаются, регистрируйте их, а также передавайте их нижележащим потокам.

0 голосов
/ 23 января 2019

Чтобы обновить среду Java 8:

После @sleske ответа

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

работал у меня из коробки.

Также было @weberjn предложение

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

, но бесполезно при обработке трафика SSL, поскольку он создает дамп закодированного потока.

Все остальные трюки с кодом у меня не сработали, но, возможно, не слишком старались

...