通过Netty连接Squid代理时Proxy规则未生效的问题
问题重现
配置Squid代理规则阻止
http://example.com/foo/bar/1,使用Firefox访问时能正确拦截该URL、允许http://example.com/foo/bar/2;但基于Netty 4.1.19.Final + Java 1.8.0_171发送请求时,两个URL均返回200 OK,拦截规则完全不生效。
核心原因
这事儿的根源在于Netty和Firefox对HTTP代理的请求发送逻辑不一样:
- Firefox在访问HTTP(非HTTPS)地址时,会直接把完整的URL(比如
http://example.com/foo/bar/1)作为GET请求的URI发送给Squid,Squid能直接匹配你配置的路径规则。 - 但Netty默认会先发送
CONNECT请求来建立代理隧道,而CONNECT请求的URI格式是example.com:80——只有主机和端口,完全不带路径信息。Squid收到这种请求时,根本看不到/foo/bar/1这个路径,自然没法触发你的拦截规则,隧道建立后后续的请求就直接通过了。
解决方案
下面给你三个可行的解决方向,你可以根据自己的场景选:
1. 让Netty直接发送完整URL(推荐,适用于HTTP场景)
既然是HTTP目标地址,完全不需要用CONNECT隧道。我们可以修改Netty的HttpClient配置,强制它把完整URL作为请求URI发给代理:
// 创建HttpClient时自定义代理处理逻辑 HttpClient client = HttpClient.create() .proxy(proxy -> proxy .type(Proxy.HTTP) .address(new InetSocketAddress("你的Squid主机IP", 3128)) // 替换成你的代理地址 .handler((ctx, proxyAddress) -> { HttpRequest originalRequest = ctx.request(); // 对于HTTP请求,直接保留完整URI发送给代理 if (originalRequest.uri().startsWith("http://")) { ctx.setRequest(originalRequest.setUri(originalRequest.uri())); } return ctx.connect(proxyAddress); }));
这样Netty就会像Firefox一样,把带完整路径的URL发给Squid,你的拦截规则就能正常生效了。
2. 修改Squid配置适配CONNECT场景
如果之后要切换到HTTPS必须用CONNECT,那得调整Squid的规则,让它在隧道建立后检查后续的请求路径。你可以在Squid的配置文件里加这些规则:
# 先允许建立到example.com的CONNECT隧道 acl target_domain dstdomain example.com http_access allow CONNECT target_domain # 拦截指定路径的请求 acl blocked_path urlpath_regex ^/foo/bar/1$ http_access deny blocked_path # 允许其他合法请求 http_access allow all
注意:要确保Squid开启了对隧道内HTTP请求的检查能力,比如启用transparent模式,或者配置adaptation模块来解析隧道内的流量,不然Squid没法看到隧道里的请求路径。
3. 升级Netty版本
Netty在4.1.50.Final及以后的版本里,优化了HTTP代理的处理逻辑——对于HTTP目标地址,默认不再强制使用CONNECT,而是直接发送完整URL。如果你的项目允许升级依赖,直接把Netty版本升到4.1.50+,这个问题大概率会自动解决。
内容的提问来源于stack exchange,提问作者Chanaka Lakmal

