You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 18:22:48