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

Spring Framework(非Spring Boot)如何限制应用仅访问指定URL?

解决受限网络下的API请求白名单验证问题

针对你遇到的场景——应用在受限网络中因第三方API调用(含RestTemplate和第三方库如org.kohsuke.github-api)无法正常运行,且需要在测试中验证白名单规则的问题,以下是几个可行的解决方案:

1. 替换第三方库的HTTP连接器

大部分第三方HTTP库都会提供自定义HTTP客户端的入口,以org.kohsuke.github-api为例,它允许你设置自定义的HttpConnector来拦截所有请求:

// 初始化白名单
Set<String> allowedUrls = Set.of("https://api.github.com/user", "https://api.github.com/repos");

GitHub github = GitHub.connectUsingOAuth("your-token");
github.setConnector(new HttpConnector() {
    @Override
    public HttpURLConnection connect(URL url) throws IOException {
        String requestUrl = url.toString();
        // 检查当前请求URL是否在白名单内
        boolean isAllowed = allowedUrls.stream().anyMatch(requestUrl::startsWith);
        if (!isAllowed) {
            throw new IOException("Request blocked: URL not in restricted network whitelist");
        }
        return (HttpURLConnection) url.openConnection();
    }
});

这种方式直接针对第三方库的请求链路做拦截,精准可控,无需修改底层网络配置。

2. 全局代理拦截(覆盖所有HTTP请求)

通过设置JVM全局代理,将所有HTTP/HTTPS请求路由到一个自定义的本地代理服务器,由代理统一检查白名单:

步骤1:设置JVM代理属性

在测试启动时添加以下系统属性:

System.setProperty("http.proxyHost", "localhost");
System.setProperty("http.proxyPort", "8888");
System.setProperty("https.proxyHost", "localhost");
System.setProperty("https.proxyPort", "8888");

步骤2:实现简单的本地代理服务器

用Java实现一个轻量代理,拦截并校验请求URL:

public class RestrictedProxyServer {
    private Set<String> whitelist = Set.of("https://allowed-domain.com");

    public void start(int port) throws IOException {
        ServerSocket serverSocket = new ServerSocket(port);
        while (true) {
            Socket clientSocket = serverSocket.accept();
            new Thread(() -> handleClient(clientSocket)).start();
        }
    }

    private void handleClient(Socket clientSocket) {
        try (BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
             OutputStream out = clientSocket.getOutputStream()) {

            // 读取请求首行,提取URL
            String requestLine = in.readLine();
            if (requestLine == null) return;
            String url = requestLine.split(" ")[1];
            
            // 校验白名单
            if (!whitelist.stream().anyMatch(url::startsWith)) {
                out.write("HTTP/1.1 403 Forbidden\r\n\r\nBlocked by restricted policy".getBytes());
                out.flush();
                clientSocket.close();
                return;
            }

            // 放行请求,转发到目标服务器(省略转发逻辑,可自行实现)
            // ...
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

这种方案能覆盖所有基于JDK HTTP客户端的请求(包括RestTemplate和第三方库),无需逐个修改各组件的配置。

3. 字节码增强拦截(AspectJ)

如果不想修改现有代码或代理配置,可以用AspectJ织入切面,拦截所有HTTP请求的核心方法:

@Aspect
public class NetworkRestrictionAspect {
    private Set<String> allowedHosts = Set.of("api.github.com", "allowed-api.com");

    // 拦截HttpURLConnection的openConnection方法
    @Around("call(java.net.HttpURLConnection+.openConnection())")
    public Object checkWhitelist(ProceedingJoinPoint joinPoint) throws Throwable {
        Object target = joinPoint.getTarget();
        if (target instanceof HttpURLConnection) {
            URL url = ((HttpURLConnection) target).getURL();
            if (!allowedHosts.contains(url.getHost())) {
                throw new IOException("Host not allowed in restricted network");
            }
        }
        return joinPoint.proceed();
    }

    // 同时拦截RestTemplate的execute方法,确保覆盖自定义请求
    @Around("execution(* org.springframework.web.client.RestTemplate.execute(..))")
    public Object interceptRestTemplate(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        if (args[0] instanceof URI) {
            URI uri = (URI) args[0];
            if (!allowedHosts.contains(uri.getHost())) {
                throw new IOException("RestTemplate request blocked: host not in whitelist");
            }
        }
        return joinPoint.proceed();
    }
}

在测试环境中启用AspectJ的编译期或加载期织入,即可实现无侵入的全局拦截。

4. 测试环境网络隔离(Docker)

如果是集成测试,用Docker容器模拟受限网络环境更贴近真实场景:
在Dockerfile中添加iptables规则,只允许白名单域名的出站请求:

# 禁止所有默认出站请求
RUN iptables -P OUTPUT DROP
# 允许白名单域名
RUN iptables -A OUTPUT -d api.github.com -j ACCEPT
RUN iptables -A OUTPUT -d allowed-api.com -j ACCEPT
# 允许本地回环(避免应用内部通信失败)
RUN iptables -A OUTPUT -o lo -j ACCEPT

启动容器后,应用的所有网络请求都会被iptables过滤,完全模拟受限网络的行为。

内容的提问来源于stack exchange,提问作者Patrick Young

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 19:20:23