使用java.net.URL时如何打印User-Agent请求头?
如何记录java.net.URL请求的User-Agent头信息?
问题背景
我用java.net.URL打开URL时,尝试通过connection.getRequestProperties()记录请求头,但没有任何输出。调试时能看到请求头存在于connection.delegate.http.requests中,想用反射读取delegate字段,却遇到模块权限错误:
Unable to make field private final sun.net.www.protocol.https.DelegateHttpsURLConnection sun.net.www.protocol.https.HttpsURLConnectionImpl.delegate accessible: module java.base does not "opens sun.net.www.protocol.https" to unnamed module
即使添加了--add-exports java.base/sun.net.www.protocol.https=ALL-UNNAMED参数也没用,想知道怎么记录User-Agent的值。
解决方法
1. 手动设置时直接记录
如果是你自己设置的User-Agent,在设置后直接打印即可,简单可靠:
URLConnection connection = new URL("https://example.com").openConnection(); // 自定义User-Agent String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"; connection.setRequestProperty("User-Agent", userAgent); // 直接记录 LOGGER.info("User-Agent: {}", userAgent); InputStream is = connection.getInputStream();
2. 获取JDK默认的User-Agent
JDK会默认使用系统属性http.agent作为User-Agent,直接读取这个属性就能拿到默认值:
String defaultUserAgent = System.getProperty("http.agent"); LOGGER.info("Default User-Agent: {}", defaultUserAgent);
这个值就是JDK自动添加到请求里的User-Agent。
3. 修正反射参数(不推荐生产环境)
之前用--add-exports不对,需要用--add-opens来开放内部包的字段访问权限,在VM参数里添加:
--add-opens java.base/sun.net.www.protocol.https=ALL-UNNAMED --add-opens java.base/sun.net.www.protocol.http=ALL-UNNAMED
然后用反射读取内部字段:
import org.apache.commons.lang3.reflect.FieldUtils; import sun.net.www.protocol.http.HttpURLConnection; import sun.net.www.protocol.https.DelegateHttpsURLConnection; // 确保connection是HttpsURLConnectionImpl实例 if (connection instanceof sun.net.www.protocol.https.HttpsURLConnectionImpl) { try { // 读取delegate字段 DelegateHttpsURLConnection delegate = (DelegateHttpsURLConnection) FieldUtils.readField(connection, "delegate", true); // 读取delegate里的http字段 HttpURLConnection httpConn = (HttpURLConnection) FieldUtils.readField(delegate, "http", true); // 获取请求列表里的第一个请求对象 Object request = ((List<?>) FieldUtils.readField(httpConn, "requests", true)).get(0); // 读取User-Agent String userAgent = (String) FieldUtils.readField(request, "userAgent", true); LOGGER.info("User-Agent from internal: {}", userAgent); } catch (IllegalAccessException | IndexOutOfBoundsException e) { LOGGER.error("Failed to read User-Agent", e); } }
注意:这种方式依赖JDK内部实现,不同版本可能失效,不建议生产环境用。
4. 开启JDK内部日志(推荐)
JDK的sun.net.www.protocol.http.HttpURLConnection会在DEBUG级别输出完整请求信息,包括所有请求头。只要在日志框架里开启对应的日志级别就行:
比如用Logback的话,在logback.xml里加:
<logger name="sun.net.www.protocol.http.HttpURLConnection" level="DEBUG"/>
这样日志里会自动输出请求的User-Agent等头信息。
内容的提问来源于stack exchange,提问作者carlos palma
相关产品推荐
相关产品推荐

