Java 8中如何优雅拦截java.net.HttpURLConnection的请求URL?
解决Java 8中HttpURLConnection的URL改写与请求/响应拦截问题
核心实现思路
通过自定义URLStreamHandler改写请求URL,同时实现一个代理HttpURLConnection类包装真实连接实例,既委托底层HTTP栈处理核心逻辑,又能优雅拦截请求头、请求内容和响应内容。
完整代码实现
1. 代理HttpURLConnection类(实现拦截与委托)
这个类负责包装真实的HttpURLConnection,重写需要拦截的方法,同时将核心逻辑委托给真实连接:
import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.util.Map; public class DelegatingHttpURLConnection extends HttpURLConnection { private final HttpURLConnection delegate; public DelegatingHttpURLConnection(HttpURLConnection delegate) { super(delegate.getURL()); this.delegate = delegate; } // 委托connect方法给真实连接,让底层HTTP栈处理核心流程 @Override public void connect() throws IOException { // 可在此添加连接前的自定义逻辑,比如统一注入通用请求头 delegate.setRequestProperty("X-Custom-Interceptor", "active"); delegate.connect(); } // 拦截请求头设置,支持修改或记录 @Override public void setRequestProperty(String key, String value) { if ("Authorization".equals(key)) { // 示例:对授权头做自定义处理 String modifiedValue = "Intercepted-" + value; super.setRequestProperty(key, modifiedValue); delegate.setRequestProperty(key, modifiedValue); } else { super.setRequestProperty(key, value); delegate.setRequestProperty(key, value); } } // 拦截请求内容,通过包装输出流实现修改 @Override public OutputStream getOutputStream() throws IOException { OutputStream delegateOut = delegate.getOutputStream(); return new FilterOutputStream(delegateOut) { @Override public void write(byte[] b, int off, int len) throws IOException { // 示例:替换请求内容中的指定字段 String originalContent = new String(b, off, len); String modifiedContent = originalContent.replace("placeholder", "real-value"); super.write(modifiedContent.getBytes(), 0, modifiedContent.getBytes().length); } }; } // 拦截响应内容,通过包装输入流实现修改 @Override public InputStream getInputStream() throws IOException { InputStream delegateIn = delegate.getInputStream(); return new FilterInputStream(delegateIn) { @Override public int read(byte[] b, int off, int len) throws IOException { int readLen = super.read(b, off, len); if (readLen > 0) { // 示例:修改响应内容中的指定文本 String originalResponse = new String(b, off, readLen); String modifiedResponse = originalResponse.replace("raw-response", "processed-response"); byte[] modifiedBytes = modifiedResponse.getBytes(); System.arraycopy(modifiedBytes, 0, b, off, modifiedBytes.length); return modifiedBytes.length; } return readLen; } }; } // 其余HttpURLConnection抽象方法全部委托给真实连接 @Override public void disconnect() { delegate.disconnect(); } @Override public boolean usingProxy() { return delegate.usingProxy(); } @Override public int getResponseCode() throws IOException { return delegate.getResponseCode(); } @Override public String getRequestMethod() { return delegate.getRequestMethod(); } @Override public void setRequestMethod(String method) throws ProtocolException { delegate.setRequestMethod(method); } @Override public Map<String, java.util.List<String>> getHeaderFields() { return delegate.getHeaderFields(); } }
2. 注册自定义URLStreamHandlerFactory
在应用初始化阶段注册,实现URL改写逻辑:
import java.io.IOException; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; import java.net.URLStreamHandlerFactory; public class CustomUrlHandlerFactory implements URLStreamHandlerFactory { @Override public URLStreamHandler createURLStreamHandler(String protocol) { // 仅处理HTTP/HTTPS协议请求 if ("http".equals(protocol) || "https".equals(protocol)) { return new URLStreamHandler() { @Override protected URLConnection openConnection(URL url) throws IOException { // 1. 执行URL改写逻辑 String rewrittenUrlStr = url.toString().replace("http://origin-domain.com", "http://target-domain.com"); URL rewrittenUrl = new URL(rewrittenUrlStr); // 2. 获取底层真实的HttpURLConnection实例 HttpURLConnection realConnection = (HttpURLConnection) rewrittenUrl.openConnection(); // 3. 返回代理类,实现拦截能力 return new DelegatingHttpURLConnection(realConnection); } }; } // 其他协议使用默认处理器 return null; } } // 初始化注册(注意:URL.setURLStreamHandlerFactory全局仅能调用一次) public class AppBootstrap { public static void init() { URL.setURLStreamHandlerFactory(new CustomUrlHandlerFactory()); } }
3. 原有业务代码无需改动
public class BusinessClient { private static final String BEARER_TOKEN = "your-auth-token"; public void fetchData() throws IOException { URL requestUrl = new URL("http://origin-domain.com/api/data"); HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); httpConnection.setRequestMethod("GET"); httpConnection.setRequestProperty("Authorization", BEARER_TOKEN); int status = httpConnection.getResponseCode(); // 后续响应处理逻辑保持不变 } }
关键说明
- URL改写:在
openConnection方法中直接替换原始URL,业务代码完全无感知。 - 请求拦截:通过重写
setRequestProperty拦截请求头,包装OutputStream拦截请求内容。 - 响应拦截:包装
InputStream拦截响应内容,可按需修改或记录响应数据。 - 核心逻辑委托:所有底层HTTP连接操作(如
connect、disconnect)都直接委托给原生HttpURLConnection,无需重复实现HTTP栈逻辑。
内容的提问来源于stack exchange,提问作者PseudoAj
相关产品推荐
相关产品推荐

