简体   繁体   English

Jsoup http 日志记录

[英]Jsoup http logging

Is there a way to log the http request and response?有没有办法记录http请求和响应? Let's assume the below request让我们假设以下请求

Connection.Response res = Jsoup.connect("LOGIN_URL_HERE")
            .data("user", "USER", "pass", "PASS")
            .method(Connection.Method.POST)
            .execute();

How can I log the http request and response?如何记录 http 请求和响应? Please mind that I want the HTTP and not just the HTML that will be parsed.请注意,我想要 HTTP 而不仅仅是将被解析的 HTML。

By default jsoup uses a implementation of java.net.HttpURLConnection So I suppose you need to turn on logging for that implementation (probably: sun.net.www.protocol.http.HttpURLConnection) or for java.net .默认情况下,jsoup 使用java.net.HttpURLConnection的实现所以我想您需要为该实现(可能是: sun.net.www.protocol.http.HttpURLConnection)java.net打开日志记录。

There is a system property that will enable logging for java net utils有一个系统属性可以为 java net utils 启用日志记录

-Djavax.net.debug=all

As Jsoup lacks logging (version I'm using: 1.12.1 ) and using the -Djavax.net.debug=all JVM argument logs are too verbose, the best way I found is to decorate the HttpConnection class, so one can customize what is logged.由于Jsoup缺少日志记录(我使用的版本: 1.12.1 )并且使用-Djavax.net.debug=all JVM 参数日志过于冗长,我发现最好的方法是装饰HttpConnection类,因此可以自定义什么已记录。 To achive this, the execute method call needs to be surrounded by logging the properties of the Connection.Request and Connection.Response .为了实现这一点, execute方法调用需要通过记录Connection.RequestConnection.Response的属性来包围。

Sample implementation using SLF4J :使用SLF4J示例实现:

import org.jsoup.Connection;
import org.jsoup.helper.HttpConnection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

public class DiagnosticConnection extends HttpConnection {
    static final Logger LOG = LoggerFactory.getLogger(DiagnosticConnection.class);

    @Override
    public Connection.Response execute() throws IOException {
        log(this.request());
        Connection.Response response = super.execute();
        log(response);

        return response;
    }

    public static Connection connect(String url) {
        Connection connection = new DiagnosticConnection();
        connection.url(url);
        return connection;
    }

    private static void log(Connection.Request request) {
        LOG.info("========================================");
        LOG.info("[url] {}", request.url());
        LOG.info("== REQUEST ==");
        logBase(request);
        LOG.info("[method] {}", request.method());
        LOG.info("[data] {}", request.data());
        LOG.info("[request body] {}", request.requestBody());
    }

    private static void log(Connection.Response response) {
        LOG.info("== RESPONSE ==");
        logBase(response);
        LOG.info("[code] {}", response.statusCode());
        LOG.info("[status msg] {}", response.statusMessage());
        LOG.info("[body] {}", response.body());
        LOG.info("========================================");
    }

    private static void logBase(Connection.Base<?> base) {
        LOG.info("[headers] {}", base.headers());
        LOG.info("[cookies] {}", base.cookies());
    }

}

When using the decorator, instead of Jsoup.connect(<URL>) you should use DiagnosticConnection.connect(<URL>)使用装饰器时,您应该使用DiagnosticConnection.connect(<URL>)而不是Jsoup.connect(<URL>) DiagnosticConnection.connect(<URL>)

Based on Gergely Toth response, I have created my own LoggerHttpConnection and I'm working with that.基于Gergely Toth 的响应,我创建了自己的LoggerHttpConnection并且我正在使用它。

import android.util.Log
import org.jsoup.Connection
import org.jsoup.helper.HttpConnection
import org.jsoup.nodes.Document
import org.jsoup.parser.Parser
import java.io.InputStream
import java.net.Proxy
import java.net.URL
import javax.net.ssl.SSLSocketFactory

class LoggerHttpConnection private constructor(
    private val delegate: HttpConnection,
    private val saveFile: Boolean
) : Connection {

    private val tag = "LoggerHttpConnection"

    companion object {
        fun connect(url: String, saveFile: Boolean = false): LoggerHttpConnection {
            return LoggerHttpConnection(
                HttpConnection.connect(url) as HttpConnection,
                saveFile
            )
        }
    }

    private fun log(request: Connection.Request): String {
        Log.i(tag, "========================================")
        var line = "[url] ${request.url()}"
        var log = "$line\n\n== REQUEST ==\n"
        Log.i(tag, line)

        Log.i(tag, "== REQUEST ==")
        log += logBase(request)

        line = "[method] ${request.method()}"
        log += "$line\n"
        Log.i(tag, line)

        for (data in request.data()) {
            line = "[data] ${data.key()}=${data.value()}"
            log += "$line\n"
            Log.i(tag, line)
        }

        line = "[request body] ${request.requestBody()}"
        log += "$line\n"
        Log.i(tag, line)

        return log
    }

    private fun log(response: Connection.Response): String {
        var line = ""
        var log = "\n== RESPONSE ==\n"

        Log.i(tag, "== RESPONSE ==")
        log += logBase(response)

        line = "[code] ${response.statusCode()}"
        log += "$line\n"
        Log.i(tag, line)

        line = "[status msg] ${response.statusMessage()}"
        log += "$line\n"
        Log.i(tag, line)

        line = "[body] ${response.body()}"
        log += "$line\n"
        Log.i(tag, line)

        Log.i(tag, "========================================")

        return log
    }

    private fun logBase(base: Connection.Base<*>): String {
        var line = ""
        var log = ""
        for (header in base.headers()) {
            line = "[header] ${header.key}=${header.value}"
            log += "$line\n"
            Log.i(tag, line)
        }
        for (cookie in base.cookies()) {
            line = "[cookie] ${cookie.key}: ${cookie.value}"
            log += "$line\n"
            Log.i(tag, line)
        }
        return log
    }

    override fun execute(): Connection.Response {
        var logs = log(request())
        val response = delegate.execute()
        logs += log(response)
        if (saveFile)
            logs.saveToFile("request_log") //do something to save your log in a file if its necesary
        return response
    }

    override fun ignoreContentType(ignoreContentType: Boolean): Connection {
        delegate.ignoreContentType(ignoreContentType)
        return this
    }

    override fun postDataCharset(charset: String?): Connection {
        delegate.postDataCharset(charset)
        return this
    }

    override fun get(): Document {
        return delegate.get()
    }

    override fun post(): Document {
        return delegate.post()
    }

    /** Continue implementing necessary methods for Connection */

}

Now just declare your request using LoggerHttpConnection instead Jsoup and everything will work现在只需使用LoggerHttpConnection而不是Jsoup声明您的请求,一切都会正常工作

Connection.Response res = LoggerHttpConnection.connect("LOGIN_URL_HERE")
        .data("user", "USER", "pass", "PASS")
        .method(Connection.Method.POST)
        .execute();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM