fix UrlQuery

This commit is contained in:
Looly 2021-11-07 03:23:44 +08:00
parent a5adc9ae94
commit 941e4f39ca
5 changed files with 76 additions and 19 deletions

View File

@ -67,10 +67,13 @@ public class URLDecoder implements Serializable {
* *
* @param str 包含URL编码后的字符串 * @param str 包含URL编码后的字符串
* @param isPlusToSpace 是否+转换为空格 * @param isPlusToSpace 是否+转换为空格
* @param charset 编码 * @param charset 编码{@code null}表示不做编码
* @return 解码后的字符串 * @return 解码后的字符串
*/ */
public static String decode(String str, Charset charset, boolean isPlusToSpace) { 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); return StrUtil.str(decode(StrUtil.bytes(str, charset), isPlusToSpace), charset);
} }

View File

@ -6,9 +6,10 @@ import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.TableMap; import cn.hutool.core.map.TableMap;
import cn.hutool.core.net.FormUrlencoded;
import cn.hutool.core.net.RFC3986; import cn.hutool.core.net.RFC3986;
import cn.hutool.core.net.URLDecoder;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.Iterator; import java.util.Iterator;
@ -26,6 +27,10 @@ import java.util.Map;
public class UrlQuery { public class UrlQuery {
private final TableMap<CharSequence, CharSequence> query; private final TableMap<CharSequence, CharSequence> query;
/**
* 是否为x-www-form-urlencoded模式此模式下空格会编码为'+'
*/
private final boolean isFormUrlEncoded;
/** /**
* 构建UrlQuery * 构建UrlQuery
@ -37,6 +42,17 @@ public class UrlQuery {
return new UrlQuery(queryMap); return new UrlQuery(queryMap);
} }
/**
* 构建UrlQuery
*
* @param queryMap 初始化的查询键值对
* @param isFormUrlEncoded 是否为x-www-form-urlencoded模式此模式下空格会编码为'+'
* @return UrlQuery
*/
public static UrlQuery of(Map<? extends CharSequence, ?> queryMap, boolean isFormUrlEncoded) {
return new UrlQuery(queryMap, isFormUrlEncoded);
}
/** /**
* 构建UrlQuery * 构建UrlQuery
* *
@ -58,9 +74,21 @@ public class UrlQuery {
* @since 5.5.8 * @since 5.5.8
*/ */
public static UrlQuery of(String queryStr, Charset charset, boolean autoRemovePath) { public static UrlQuery of(String queryStr, Charset charset, boolean autoRemovePath) {
final UrlQuery urlQuery = new UrlQuery(); return of(queryStr, charset, autoRemovePath, false);
urlQuery.parse(queryStr, charset, autoRemovePath); }
return urlQuery;
/**
* 构建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<? extends CharSequence, ?> queryMap) { public UrlQuery(Map<? extends CharSequence, ?> queryMap) {
this(queryMap, false);
}
/**
* 构造
*
* @param queryMap 初始化的查询键值对
* @param isFormUrlEncoded 是否为x-www-form-urlencoded模式此模式下空格会编码为'+'
* @since 5.7.16
*/
public UrlQuery(Map<? extends CharSequence, ?> queryMap, boolean isFormUrlEncoded) {
if (MapUtil.isNotEmpty(queryMap)) { if (MapUtil.isNotEmpty(queryMap)) {
query = new TableMap<>(queryMap.size()); query = new TableMap<>(queryMap.size());
addAll(queryMap); addAll(queryMap);
} else { } else {
query = new TableMap<>(MapUtil.DEFAULT_INITIAL_CAPACITY); query = new TableMap<>(MapUtil.DEFAULT_INITIAL_CAPACITY);
} }
this.isFormUrlEncoded = isFormUrlEncoded;
} }
/** /**
@ -182,6 +232,10 @@ public class UrlQuery {
* @return URL查询字符串 * @return URL查询字符串
*/ */
public String build(Charset charset) { 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); 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) { private void addParam(String key, String value, Charset charset) {
if (null != key) { if (null != key) {
final String actualKey = URLUtil.decode(key, charset); final String actualKey = URLDecoder.decode(key, charset, isFormUrlEncoded);
this.query.put(actualKey, StrUtil.nullToEmpty(URLUtil.decode(value, charset))); this.query.put(actualKey, StrUtil.nullToEmpty(URLDecoder.decode(value, charset, isFormUrlEncoded)));
} else if (null != value) { } else if (null != value) {
// name为空value作为namevalue赋值null // name为空value作为namevalue赋值null
this.query.put(URLUtil.decode(value, charset), null); this.query.put(URLDecoder.decode(value, charset, isFormUrlEncoded), null);
} }
} }
} }

View File

@ -328,9 +328,6 @@ public class URLUtil extends URLEncodeUtil {
* @since 4.4.1 * @since 4.4.1
*/ */
public static String decode(String content, Charset charset) { public static String decode(String content, Charset charset) {
if (null == charset) {
return content;
}
return URLDecoder.decode(content, charset); return URLDecoder.decode(content, charset);
} }
@ -345,9 +342,6 @@ public class URLUtil extends URLEncodeUtil {
* @since 5.6.3 * @since 5.6.3
*/ */
public static String decode(String content, Charset charset, boolean isPlusToSpace) { public static String decode(String content, Charset charset, boolean isPlusToSpace) {
if (null == charset) {
return content;
}
return URLDecoder.decode(content, charset, isPlusToSpace); return URLDecoder.decode(content, charset, isPlusToSpace);
} }
@ -361,7 +355,7 @@ public class URLUtil extends URLEncodeUtil {
* @throws UtilException UnsupportedEncodingException * @throws UtilException UnsupportedEncodingException
*/ */
public static String decode(String content, String charset) throws UtilException { 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));
} }
/** /**

View File

@ -108,6 +108,14 @@ public class UrlQueryTest {
Assert.assertEquals("a+b=1+2", a); 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 @Test
public void spaceTest(){ public void spaceTest(){
// 根据RFC3986在URL中空格编码为"%20" // 根据RFC3986在URL中空格编码为"%20"

View File

@ -10,7 +10,6 @@ import cn.hutool.core.io.resource.MultiFileResource;
import cn.hutool.core.io.resource.Resource; import cn.hutool.core.io.resource.Resource;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.net.FormUrlencoded;
import cn.hutool.core.net.SSLUtil; import cn.hutool.core.net.SSLUtil;
import cn.hutool.core.net.url.UrlBuilder; import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.net.url.UrlQuery; import cn.hutool.core.net.url.UrlQuery;
@ -1229,8 +1228,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
* @since 5.3.2 * @since 5.3.2
*/ */
private String getFormUrlEncoded() { private String getFormUrlEncoded() {
return UrlQuery.of(this.form) return UrlQuery.of(this.form, true).build(this.charset);
.build(FormUrlencoded.ALL, FormUrlencoded.ALL, this.charset);
} }
/** /**