diff --git a/CHANGELOG.md b/CHANGELOG.md index 44dbfe5a5..796f2cdf7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ # 🚀Changelog ------------------------------------------------------------------------------------------------------------- -# 5.7.22 (2022-02-22) +# 5.7.22 (2022-02-23) ### 🐣新特性 * 【poi 】 ExcelUtil.readBySax增加对POI-5.2.0的兼容性(issue#I4TJF4@gitee) @@ -13,6 +13,7 @@ * 【core 】 CheckedUtil删除第二个参数为RuntimeException的方法 * 【core 】 FileUtil增加getTotalLines方法 * 【db 】 MetaUtil增加getTableMeta重载(issue#2157@Github) +* 【http 】 增加HttpGlobalConfig.setDecodeUrl(issue#I4U8YQ@Gitee) ### 🐞Bug修复 * 【cache 】 修复ReentrantCache.toString方法线程不安全问题(issue#2140@Github) diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpBase.java b/hutool-http/src/main/java/cn/hutool/http/HttpBase.java index b39c6e8ad..8b3ebe441 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpBase.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpBase.java @@ -24,6 +24,11 @@ import java.util.Map.Entry; @SuppressWarnings("unchecked") public abstract class HttpBase { + /** + * 默认的请求编码、URL的encode、decode编码 + */ + protected static final Charset DEFAULT_CHARSET = CharsetUtil.CHARSET_UTF_8; + /** * HTTP/1.0 */ @@ -40,7 +45,7 @@ public abstract class HttpBase { /** * 编码 */ - protected Charset charset = CharsetUtil.CHARSET_UTF_8; + protected Charset charset = DEFAULT_CHARSET; /** * http版本 */ diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpGlobalConfig.java b/hutool-http/src/main/java/cn/hutool/http/HttpGlobalConfig.java index 99f28b1e1..2015bdc77 100755 --- a/hutool-http/src/main/java/cn/hutool/http/HttpGlobalConfig.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpGlobalConfig.java @@ -33,6 +33,7 @@ public class HttpGlobalConfig implements Serializable { private static String boundary = "--------------------Hutool_" + RandomUtil.randomString(16); private static int maxRedirectCount = 0; private static boolean ignoreEOFError = true; + private static boolean decodeUrl = false; /** * 获取全局默认的超时时长 @@ -124,12 +125,36 @@ public class HttpGlobalConfig implements Serializable { ignoreEOFError = customIgnoreEOFError; } + /** + * 获取是否忽略解码URL,包括URL中的Path部分和Param部分。
+ * 在构建Http请求时,用户传入的URL可能有编码后和未编码的内容混合在一起,如果此参数为{@code true},则会统一解码编码后的参数,
+ * 按照RFC3986规范,在发送请求时,全部编码之。如果为{@code false},则不会解码已经编码的内容,在请求时只编码需要编码的部分。 + * + * @return 是否忽略解码URL + * @since 5.7.22 + */ + public static boolean isDecodeUrl() { + return decodeUrl; + } + + /** + * 设置是否忽略解码URL,包括URL中的Path部分和Param部分。
+ * 在构建Http请求时,用户传入的URL可能有编码后和未编码的内容混合在一起,如果此参数为{@code true},则会统一解码编码后的参数,
+ * 按照RFC3986规范,在发送请求时,全部编码之。如果为{@code false},则不会解码已经编码的内容,在请求时只编码需要编码的部分。 + * + * @param customDecodeUrl 是否忽略解码URL + * @since 5.7.22 + */ + synchronized public static void setDecodeUrl(boolean customDecodeUrl) { + decodeUrl = customDecodeUrl; + } + /** * 获取Cookie管理器,用于自定义Cookie管理 * * @return {@link CookieManager} - * @since 4.1.0 * @see GlobalCookieManager#getCookieManager() + * @since 4.1.0 */ public static CookieManager getCookieManager() { return GlobalCookieManager.getCookieManager(); @@ -139,8 +164,8 @@ public class HttpGlobalConfig implements Serializable { * 自定义{@link CookieManager} * * @param customCookieManager 自定义的{@link CookieManager} - * @since 4.5.14 * @see GlobalCookieManager#setCookieManager(CookieManager) + * @since 4.5.14 */ synchronized public static void setCookieManager(CookieManager customCookieManager) { GlobalCookieManager.setCookieManager(customCookieManager); @@ -149,8 +174,8 @@ public class HttpGlobalConfig implements Serializable { /** * 关闭Cookie * - * @since 4.1.9 * @see GlobalCookieManager#setCookieManager(CookieManager) + * @since 4.1.9 */ synchronized public static void closeCookie() { GlobalCookieManager.setCookieManager(null); @@ -164,7 +189,7 @@ public class HttpGlobalConfig implements Serializable { * @since 5.7.4 */ synchronized public static void allowPatch() { - if(isAllowPatch){ + if (isAllowPatch) { return; } final Field methodsField = ReflectUtil.getField(HttpURLConnection.class, "methods"); @@ -181,7 +206,7 @@ public class HttpGlobalConfig implements Serializable { // 检查注入是否成功 final Object staticFieldValue = ReflectUtil.getStaticFieldValue(methodsField); - if(false == ArrayUtil.equals(methods, staticFieldValue)){ + if (false == ArrayUtil.equals(methods, staticFieldValue)) { throw new HttpException("Inject value to field [methods] failed!"); } diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java index 7c7a68e35..864363e19 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java @@ -12,7 +12,6 @@ import cn.hutool.core.map.MapUtil; import cn.hutool.core.net.SSLUtil; import cn.hutool.core.net.url.UrlBuilder; import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.body.BytesBody; @@ -129,18 +128,24 @@ public class HttpRequest extends HttpBase { } /** - * 构建一个HTTP请求 + * 构建一个HTTP请求
+ * 对于传入的URL,可以自定义是否解码已经编码的内容,设置见{@link HttpGlobalConfig#setDecodeUrl(boolean)}
+ * 在构建Http请求时,用户传入的URL可能有编码后和未编码的内容混合在一起,如果{@link HttpGlobalConfig#isDecodeUrl()}为{@code true},则会统一解码编码后的参数,
+ * 按照RFC3986规范,在发送请求时,全部编码之。如果为{@code false},则不会解码已经编码的内容,在请求时只编码需要编码的部分。 * * @param url URL链接,默认自动编码URL中的参数等信息 * @return HttpRequest * @since 5.7.18 */ public static HttpRequest of(String url) { - return of(url, CharsetUtil.CHARSET_UTF_8); + return of(url, HttpGlobalConfig.isDecodeUrl() ? DEFAULT_CHARSET : null); } /** - * 构建一个HTTP请求 + * 构建一个HTTP请求
+ * 对于传入的URL,可以自定义是否解码已经编码的内容。
+ * 在构建Http请求时,用户传入的URL可能有编码后和未编码的内容混合在一起,如果charset参数不为{@code null},则会统一解码编码后的参数,
+ * 按照RFC3986规范,在发送请求时,全部编码之。如果为{@code false},则不会解码已经编码的内容,在请求时只编码需要编码的部分。 * * @param url URL链接 * @param charset 编码,如果为{@code null}不自动解码编码URL @@ -266,7 +271,9 @@ public class HttpRequest extends HttpBase { * 构造,URL编码默认使用UTF-8 * * @param url URL + * @deprecated 请使用 {@link #of(String)} */ + @Deprecated public HttpRequest(String url) { this(UrlBuilder.ofHttp(url)); } diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java b/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java index a6904f6f4..2ed832948 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java @@ -75,7 +75,7 @@ public class HttpUtil { * @since 3.0.9 */ public static HttpRequest createRequest(Method method, String url) { - return new HttpRequest(url).method(method); + return HttpRequest.of(url).method(method); } /** diff --git a/hutool-http/src/test/java/cn/hutool/http/HttpUtilTest.java b/hutool-http/src/test/java/cn/hutool/http/HttpUtilTest.java index 7853751aa..18dbb9682 100644 --- a/hutool-http/src/test/java/cn/hutool/http/HttpUtilTest.java +++ b/hutool-http/src/test/java/cn/hutool/http/HttpUtilTest.java @@ -3,7 +3,6 @@ package cn.hutool.http; import cn.hutool.core.codec.Base64; import cn.hutool.core.io.FileUtil; import cn.hutool.core.lang.Console; -import cn.hutool.core.net.url.UrlBuilder; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.ReUtil; import org.junit.Assert; @@ -357,11 +356,10 @@ public class HttpUtilTest { @Test @Ignore public void getPicTest(){ + HttpGlobalConfig.setDecodeUrl(false); String url = "https://p3-sign.douyinpic.com/tos-cn-i-0813/f41afb2e79a94dcf80970affb9a69415~noop.webp?x-expires=1647738000&x-signature=%2Br1ekUCGjXiu50Y%2Bk0MO4ovulK8%3D&from=4257465056&s=PackSourceEnum_DOUYIN_REFLOW&se=false&sh=&sc=&l=2022021809224601020810013524310DD3&biz_tag=aweme_images"; - final String s = UrlBuilder.ofHttp(url).toString(); - // Assert.assertEquals(url, s); - final HttpRequest request = HttpRequest.of(url, null).method(Method.GET); + final HttpRequest request = HttpRequest.of(url).method(Method.GET); Console.log(request.execute().body()); } }