From 941e4f39caad39e2b63eeae6c2b91aad2f216a4e Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 7 Nov 2021 03:23:44 +0800 Subject: [PATCH] fix UrlQuery --- .../java/cn/hutool/core/net/URLDecoder.java | 5 +- .../java/cn/hutool/core/net/url/UrlQuery.java | 70 ++++++++++++++++--- .../java/cn/hutool/core/util/URLUtil.java | 8 +-- .../java/cn/hutool/core/net/UrlQueryTest.java | 8 +++ .../main/java/cn/hutool/http/HttpRequest.java | 4 +- 5 files changed, 76 insertions(+), 19 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/net/URLDecoder.java b/hutool-core/src/main/java/cn/hutool/core/net/URLDecoder.java index bd0adc849..106d973e4 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/URLDecoder.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/URLDecoder.java @@ -67,10 +67,13 @@ public class URLDecoder implements Serializable { * * @param str 包含URL编码后的字符串 * @param isPlusToSpace 是否+转换为空格 - * @param charset 编码 + * @param charset 编码,{@code null}表示不做编码 * @return 解码后的字符串 */ public static String decode(String str, Charset charset, boolean isPlusToSpace) { + if(null == charset){ + return str; + } return StrUtil.str(decode(StrUtil.bytes(str, charset), isPlusToSpace), charset); } diff --git a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java index 2476f578c..6260c727a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java @@ -6,9 +6,10 @@ import cn.hutool.core.collection.IterUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.TableMap; +import cn.hutool.core.net.FormUrlencoded; import cn.hutool.core.net.RFC3986; +import cn.hutool.core.net.URLDecoder; import cn.hutool.core.util.StrUtil; -import cn.hutool.core.util.URLUtil; import java.nio.charset.Charset; import java.util.Iterator; @@ -26,6 +27,10 @@ import java.util.Map; public class UrlQuery { private final TableMap query; + /** + * 是否为x-www-form-urlencoded模式,此模式下空格会编码为'+' + */ + private final boolean isFormUrlEncoded; /** * 构建UrlQuery @@ -37,6 +42,17 @@ public class UrlQuery { return new UrlQuery(queryMap); } + /** + * 构建UrlQuery + * + * @param queryMap 初始化的查询键值对 + * @param isFormUrlEncoded 是否为x-www-form-urlencoded模式,此模式下空格会编码为'+' + * @return UrlQuery + */ + public static UrlQuery of(Map queryMap, boolean isFormUrlEncoded) { + return new UrlQuery(queryMap, isFormUrlEncoded); + } + /** * 构建UrlQuery * @@ -58,9 +74,21 @@ public class UrlQuery { * @since 5.5.8 */ public static UrlQuery of(String queryStr, Charset charset, boolean autoRemovePath) { - final UrlQuery urlQuery = new UrlQuery(); - urlQuery.parse(queryStr, charset, autoRemovePath); - return urlQuery; + return of(queryStr, charset, autoRemovePath, false); + } + + /** + * 构建UrlQuery + * + * @param queryStr 初始化的查询字符串 + * @param charset decode用的编码,null表示不做decode + * @param autoRemovePath 是否自动去除path部分,{@code true}则自动去除第一个?前的内容 + * @param isFormUrlEncoded 是否为x-www-form-urlencoded模式,此模式下空格会编码为'+' + * @return UrlQuery + * @since 5.7.16 + */ + public static UrlQuery of(String queryStr, Charset charset, boolean autoRemovePath, boolean isFormUrlEncoded) { + return new UrlQuery(isFormUrlEncoded).parse(queryStr, charset, autoRemovePath); } /** @@ -73,15 +101,37 @@ public class UrlQuery { /** * 构造 * - * @param queryMap 初始化的查询键值对 + * @param isFormUrlEncoded 是否为x-www-form-urlencoded模式,此模式下空格会编码为'+' + * @since 5.7.16 + */ + public UrlQuery(boolean isFormUrlEncoded) { + this(null, isFormUrlEncoded); + } + + /** + * 构造 + * + * @param queryMap 初始化的查询键值对 */ public UrlQuery(Map queryMap) { + this(queryMap, false); + } + + /** + * 构造 + * + * @param queryMap 初始化的查询键值对 + * @param isFormUrlEncoded 是否为x-www-form-urlencoded模式,此模式下空格会编码为'+' + * @since 5.7.16 + */ + public UrlQuery(Map queryMap, boolean isFormUrlEncoded) { if (MapUtil.isNotEmpty(queryMap)) { query = new TableMap<>(queryMap.size()); addAll(queryMap); } else { query = new TableMap<>(MapUtil.DEFAULT_INITIAL_CAPACITY); } + this.isFormUrlEncoded = isFormUrlEncoded; } /** @@ -182,6 +232,10 @@ public class UrlQuery { * @return URL查询字符串 */ public String build(Charset charset) { + if (isFormUrlEncoded) { + return build(FormUrlencoded.ALL, FormUrlencoded.ALL, charset); + } + return build(RFC3986.QUERY_PARAM_NAME, RFC3986.QUERY_PARAM_VALUE, charset); } @@ -315,11 +369,11 @@ public class UrlQuery { */ private void addParam(String key, String value, Charset charset) { if (null != key) { - final String actualKey = URLUtil.decode(key, charset); - this.query.put(actualKey, StrUtil.nullToEmpty(URLUtil.decode(value, charset))); + final String actualKey = URLDecoder.decode(key, charset, isFormUrlEncoded); + this.query.put(actualKey, StrUtil.nullToEmpty(URLDecoder.decode(value, charset, isFormUrlEncoded))); } else if (null != value) { // name为空,value作为name,value赋值null - this.query.put(URLUtil.decode(value, charset), null); + this.query.put(URLDecoder.decode(value, charset, isFormUrlEncoded), null); } } } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java index 5745bce89..724312695 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java @@ -328,9 +328,6 @@ public class URLUtil extends URLEncodeUtil { * @since 4.4.1 */ public static String decode(String content, Charset charset) { - if (null == charset) { - return content; - } return URLDecoder.decode(content, charset); } @@ -345,9 +342,6 @@ public class URLUtil extends URLEncodeUtil { * @since 5.6.3 */ public static String decode(String content, Charset charset, boolean isPlusToSpace) { - if (null == charset) { - return content; - } return URLDecoder.decode(content, charset, isPlusToSpace); } @@ -361,7 +355,7 @@ public class URLUtil extends URLEncodeUtil { * @throws UtilException UnsupportedEncodingException */ public static String decode(String content, String charset) throws UtilException { - return decode(content, CharsetUtil.charset(charset)); + return decode(content, StrUtil.isEmpty(charset) ? null : CharsetUtil.charset(charset)); } /** diff --git a/hutool-core/src/test/java/cn/hutool/core/net/UrlQueryTest.java b/hutool-core/src/test/java/cn/hutool/core/net/UrlQueryTest.java index ca5f9581a..4bdaabc0d 100644 --- a/hutool-core/src/test/java/cn/hutool/core/net/UrlQueryTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/net/UrlQueryTest.java @@ -108,6 +108,14 @@ public class UrlQueryTest { Assert.assertEquals("a+b=1+2", a); } + @Test + public void parsePlusTest(){ + // 根据RFC3986,在URL中,+是安全字符,即此符号不转义 + final String a = UrlQuery.of("a+b=1+2", CharsetUtil.CHARSET_UTF_8) + .build(CharsetUtil.CHARSET_UTF_8); + Assert.assertEquals("a+b=1+2", a); + } + @Test public void spaceTest(){ // 根据RFC3986,在URL中,空格编码为"%20" 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 ae4e196f2..f52f570f2 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java @@ -10,7 +10,6 @@ import cn.hutool.core.io.resource.MultiFileResource; import cn.hutool.core.io.resource.Resource; import cn.hutool.core.lang.Assert; import cn.hutool.core.map.MapUtil; -import cn.hutool.core.net.FormUrlencoded; import cn.hutool.core.net.SSLUtil; import cn.hutool.core.net.url.UrlBuilder; import cn.hutool.core.net.url.UrlQuery; @@ -1229,8 +1228,7 @@ public class HttpRequest extends HttpBase { * @since 5.3.2 */ private String getFormUrlEncoded() { - return UrlQuery.of(this.form) - .build(FormUrlencoded.ALL, FormUrlencoded.ALL, this.charset); + return UrlQuery.of(this.form, true).build(this.charset); } /**