add proxy support

This commit is contained in:
Looly
2025-10-23 02:38:54 +08:00
parent 9ab781090d
commit 0b2565f6aa
23 changed files with 234 additions and 221 deletions

View File

@@ -18,6 +18,7 @@ package cn.hutool.v7.http;
import cn.hutool.v7.core.util.RandomUtil;
import java.io.Serial;
import java.io.Serializable;
import java.net.HttpURLConnection;
@@ -28,6 +29,7 @@ import java.net.HttpURLConnection;
* @since 4.6.2
*/
public class HttpGlobalConfig implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
@@ -168,7 +170,7 @@ public class HttpGlobalConfig implements Serializable {
/**
* 是否信任所有Host<br>
* 见https://github.com/chinabugotech/hutool/issues/2042<br>
* 见:<a href="https://github.com/chinabugotech/hutool/issues/2042">issue#2042</a><br>
*
* @param customTrustAnyHost 如果设置为{@code false}则按照JDK默认验证机制验证目标服务器的证书host和请求host是否一致{@code true}表示不验证。
* @since 5.8.27

View File

@@ -19,7 +19,6 @@ package cn.hutool.v7.http;
import cn.hutool.v7.core.collection.CollUtil;
import cn.hutool.v7.core.map.CaseInsensitiveMap;
import cn.hutool.v7.core.map.MapUtil;
import cn.hutool.v7.core.net.url.UrlQueryUtil;
import cn.hutool.v7.core.text.StrUtil;
import cn.hutool.v7.http.client.ClientConfig;
import cn.hutool.v7.http.client.Request;
@@ -208,75 +207,6 @@ public class HttpUtil {
return ClientEngineFactory.getEngine().send(request);
}
/**
* 将表单数据加到URL中用于GET表单提交
* 表单的键值对会被url编码但是url中原参数不会被编码
* 且对form参数进行 FormUrlEncoded x-www-form-urlencoded模式此模式下空格会编码为'+'
*
* @param url URL
* @param form 表单数据
* @param charset 编码 null表示不encode键值对
* @return 合成后的URL
*/
public static String urlWithFormUrlEncoded(final String url, final Map<String, Object> form, final Charset charset) {
return urlWithForm(url, form, charset, true);
}
/**
* 将表单数据加到URL中用于GET表单提交<br>
* 表单的键值对会被url编码但是url中原参数不会被编码
*
* @param url URL
* @param form 表单数据
* @param charset 编码
* @param isEncodeParams 是否对键和值做转义处理
* @return 合成后的URL
*/
public static String urlWithForm(final String url, final Map<String, Object> form, final Charset charset, final boolean isEncodeParams) {
return urlWithForm(url, UrlQueryUtil.toQuery(form, null), charset, isEncodeParams);
}
/**
* 将表单数据字符串加到URL中用于GET表单提交
*
* @param url URL
* @param queryString 表单数据字符串
* @param charset 编码
* @param isEncode 是否对键和值做转义处理
* @return 拼接后的字符串
*/
public static String urlWithForm(final String url, final String queryString, final Charset charset, final boolean isEncode) {
if (StrUtil.isBlank(queryString)) {
// 无额外参数
if (StrUtil.contains(url, '?')) {
// url中包含参数
return isEncode ? UrlQueryUtil.encodeQuery(url, charset) : url;
}
return url;
}
// 始终有参数
final StringBuilder urlBuilder = new StringBuilder(url.length() + queryString.length() + 16);
final int qmIndex = url.indexOf('?');
if (qmIndex > 0) {
// 原URL带参数则对这部分参数单独编码如果选项为进行编码
urlBuilder.append(isEncode ? UrlQueryUtil.encodeQuery(url, charset) : url);
if (!StrUtil.endWith(url, '&')) {
// 已经带参数的情况下追加参数
urlBuilder.append('&');
}
} else {
// 原url无参数则不做编码
urlBuilder.append(url);
if (qmIndex < 0) {
// 无 '?' 追加之
urlBuilder.append('?');
}
}
urlBuilder.append(isEncode ? UrlQueryUtil.encodeQuery(queryString, charset) : queryString);
return urlBuilder.toString();
}
/**
* 创建客户端引擎
*

View File

@@ -28,7 +28,6 @@ import cn.hutool.v7.http.ssl.SSLInfo;
import java.io.IOException;
import java.io.InputStream;
import java.net.ProxySelector;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

View File

@@ -30,19 +30,9 @@ import java.net.PasswordAuthentication;
*
* @author Looly
* @since 6.0.0
* @param auth 账号密码
*/
public class BasicProxyAuthenticator implements Authenticator {
private final PasswordAuthentication auth;
/**
* 构造
*
* @param passwordAuthentication 账号密码对
*/
public BasicProxyAuthenticator(final PasswordAuthentication passwordAuthentication) {
auth = passwordAuthentication;
}
public record BasicProxyAuthenticator(PasswordAuthentication auth) implements Authenticator {
@Override
public Request authenticate(final Route route, final Response response) {

View File

@@ -31,26 +31,17 @@ import java.util.List;
*
* @author Looly
* @since 6.0.0
* @param cookieStore Cookie存储器用于自定义Cookie存储实现
*/
public class CookieJarImpl implements CookieJar {
private final CookieStoreSpi cookieStore;
/**
* 构造
*
* @param cookieStore Cookie存储器用于自定义Cookie存储实现
*/
public CookieJarImpl(final CookieStoreSpi cookieStore) {
this.cookieStore = cookieStore;
}
public record CookieJarImpl(CookieStoreSpi cookieStore) implements CookieJar {
/**
* 获取Cookie存储器
*
* @return Cookie存储器
*/
public CookieStoreSpi getCookieStore() {
@Override
public CookieStoreSpi cookieStore() {
return this.cookieStore;
}
@@ -59,14 +50,14 @@ public class CookieJarImpl implements CookieJar {
final List<CookieSpi> cookieSpis = this.cookieStore.get(httpUrl.uri());
final List<Cookie> cookies = new ArrayList<>(cookieSpis.size());
for (final CookieSpi cookieSpi : cookieSpis) {
cookies.add(((OkCookie)cookieSpi).getRaw());
cookies.add(((OkCookie) cookieSpi).getRaw());
}
return cookies;
}
@Override
public void saveFromResponse(final HttpUrl httpUrl, final List<Cookie> list) {
if(CollUtil.isEmpty(list)){
if (CollUtil.isEmpty(list)) {
return;
}

View File

@@ -28,7 +28,6 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -131,30 +130,6 @@ public class HttpUtilTest {
Console.log(body);
}
@Test
public void urlWithFormTest() {
final Map<String, Object> param = new LinkedHashMap<>();
param.put("AccessKeyId", "123");
param.put("Action", "DescribeDomainRecords");
param.put("Format", "date");
param.put("DomainName", "lesper.cn"); // 域名地址
param.put("SignatureMethod", "POST");
param.put("SignatureNonce", "123");
param.put("SignatureVersion", "4.3.1");
param.put("Timestamp", 123432453);
param.put("Version", "1.0");
String urlWithForm = HttpUtil.urlWithForm("http://api.hutool.cn/login?type=aaa", param, CharsetUtil.UTF_8, false);
Assertions.assertEquals(
"http://api.hutool.cn/login?type=aaa&AccessKeyId=123&Action=DescribeDomainRecords&Format=date&DomainName=lesper.cn&SignatureMethod=POST&SignatureNonce=123&SignatureVersion=4.3.1&Timestamp=123432453&Version=1.0",
urlWithForm);
urlWithForm = HttpUtil.urlWithForm("http://api.hutool.cn/login?type=aaa", param, CharsetUtil.UTF_8, false);
Assertions.assertEquals(
"http://api.hutool.cn/login?type=aaa&AccessKeyId=123&Action=DescribeDomainRecords&Format=date&DomainName=lesper.cn&SignatureMethod=POST&SignatureNonce=123&SignatureVersion=4.3.1&Timestamp=123432453&Version=1.0",
urlWithForm);
}
@Test
@Disabled
public void getWeixinTest(){

View File

@@ -18,6 +18,7 @@ package cn.hutool.v7.http;
import cn.hutool.v7.core.net.url.UrlQuery;
import cn.hutool.v7.core.net.url.UrlQueryUtil;
import cn.hutool.v7.core.net.url.UrlUtil;
import cn.hutool.v7.core.util.CharsetUtil;
import org.junit.jupiter.api.Test;
@@ -35,7 +36,7 @@ public class Issue3536Test {
paramMap.put("redirect_uri", "https://api.hutool.cn/v1/test");
paramMap.put("scope", "a,b,c你");
final String s = HttpUtil.urlWithFormUrlEncoded(url, paramMap, CharsetUtil.UTF_8);
final String s = UrlUtil.urlWithFormUrlEncoded(url, paramMap, CharsetUtil.UTF_8);
assertEquals("https://hutool.cn/test?scope=a,b,c%E4%BD%A0&redirect_uri=https://api.hutool.cn/v1/test", s);
}

View File

@@ -18,6 +18,7 @@ package cn.hutool.v7.http;
import cn.hutool.v7.core.collection.ListUtil;
import cn.hutool.v7.core.net.url.UrlQuery;
import cn.hutool.v7.core.net.url.UrlUtil;
import cn.hutool.v7.core.util.CharsetUtil;
import cn.hutool.v7.json.JSONObject;
import cn.hutool.v7.json.JSONUtil;
@@ -39,12 +40,12 @@ public class IssueIAFKWPTest {
// form-url-encoded模式下所有字符转义
String build = UrlQuery.of(params, UrlQuery.EncodeMode.FORM_URL_ENCODED).build(CharsetUtil.UTF_8);
String s = HttpUtil.urlWithForm("https://hutool.cn", build, CharsetUtil.UTF_8, false);
String s = UrlUtil.urlWithForm("https://hutool.cn", build, CharsetUtil.UTF_8, false);
Assertions.assertEquals("https://hutool.cn?query=%7B%22fields%22%3A%5B%221%22%2C%222%22%2C%22good%22%5D%7D", s);
// 标准模式下只转义特定字符
build = UrlQuery.of(params, UrlQuery.EncodeMode.NORMAL).build(CharsetUtil.UTF_8);
s = HttpUtil.urlWithForm("https://hutool.cn", build, CharsetUtil.UTF_8, false);
s = UrlUtil.urlWithForm("https://hutool.cn", build, CharsetUtil.UTF_8, false);
Assertions.assertEquals("https://hutool.cn?query=%7B%22fields%22:%5B%221%22,%222%22,%22good%22%5D%7D", s);
}
}