环境:网闸(前置机,也就是能访问公网的服务器172.168.10.1)、内网服务器(微信小程序应用部署服务器192.168.80.1)
最好的方式是服务器层面处理,网络这一块是知识盲区。
问题:进入 docker 容器内部执行:
curl -v -x http://172.168.10.1:7788\
'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=123&secret=45678'
能正常拿到token,但是 java 增加了代理配置:
wx:
mp:
app-id: 123
secret: 45678
config-storage:
type: RedisTemplate
key-prefix: wx
http-client-type: HttpClient
http-proxy-host: 172.168.10.1 # 代理 ip
http-proxy-port: 7788 # 代理端口
大概是这样:透明代理
在服务器层做 透明代理:
例如:
iptables
clash
squid
redsocks
自动把:
api.weixin.qq.com:443
转发到代理。
程序完全不知道代理存在。
架构:
Java
↓
iptables
↓
proxy
↓
WeChat
这是 大型公司最常见方案。
wx:
mp:
app-id: 123
secret: 45678
config-storage:
type: RedisTemplate
key-prefix: wx
http-client-type: HttpClient
http-proxy-host: 172.168.10.1
http-proxy-port: 7788
这种方式配置代理,但是 java 在发请求的时候,设置不了代理。所以,启动容器的命令新增:
docker run -d --restart=always \
-p 9210:9210 \
-v /opt/test-server/logs:/test-server/logs \
-v /opt/test-server/conf:/test-server/config \
-e JAVA_TOOL_OPTIONS="
-Dhttp.proxyHost=172.168.10.1
-Dhttp.proxyPort=7788
-Dhttps.proxyHost=172.168.10.1
-Dhttps.proxyPort=7788
-Dhttp.nonProxyHosts=localhost|127.*|10.*|172.*|192.168.*" \
--name dpf-server \
--privileged \
test-server:1.0.0
JVM 的系统属性 (System Properties)。
JDK 网络库在发 HTTP 请求时会自动读取这些参数。
你项目里实际用的是 JDK11 的 HttpClient:
java.net.http.HttpClient
这个客户端默认使用:
ProxySelector.getDefault()
而 ProxySelector 会读取 JVM 的这些系统属性:
| 属性 | 作用 |
|---|---|
| http.proxyHost | HTTP 代理地址 |
| http.proxyPort | HTTP 代理端口 |
| https.proxyHost | HTTPS 代理地址 |
| https.proxyPort | HTTPS 代理端口 |
| http.nonProxyHosts | 不走代理的地址 |
所以请求流程就变成:
Java HttpClient
↓
ProxySelector (读取 JVM 参数)
↓
http://172.18.181.5:9216
↓
CONNECT api.weixin.qq.com:443
↓
微信服务器
↓
ProxySelector (读取 JVM 参数)
↓
http://172.18.181.5:9216
↓
CONNECT api.weixin.qq.com:443
↓
微信服务器
这就是为什么你一加参数就成功。
二、http.nonProxyHosts 的作用
你加的:
localhost|127.*|10.*|172.*|192.168.*
意思是:
这些地址 不走代理。
例如:
http://127.0.0.1
http://10.x.x.x
http://172.x.x.x
http://192.168.x.x
http://10.x.x.x
http://172.x.x.x
http://192.168.x.x
请求流程:
Java → 直接连接
否则:
Java → 代理 → 目标服务器
避免了 内网请求被代理。
三、为什么不配置就不走代理
Java 默认:
ProxySelector = DIRECT
意思是:
Java → 目标服务器
不会自动识别:
-
Linux
http_proxy -
curl 代理
-
系统代理
所以你:
curl -x proxy
可以。
但 Java 不行。