This commit is contained in:
Looly 2021-11-07 02:34:03 +08:00
parent 065c6d61c8
commit a5adc9ae94
11 changed files with 71 additions and 36 deletions

View File

@ -3,7 +3,7 @@
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.7.16 (2021-11-04) # 5.7.16 (2021-11-07)
### 🐣新特性 ### 🐣新特性
* 【core 】 增加DateTime.toLocalDateTime * 【core 】 增加DateTime.toLocalDateTime
@ -35,6 +35,7 @@
* 【core 】 修复CompilerUtil.getFileManager参数没有使用的问题issue#I4FIO6@Gitee * 【core 】 修复CompilerUtil.getFileManager参数没有使用的问题issue#I4FIO6@Gitee
* 【core 】 修复NetUtil.isInRange的cidr判断问题pr#1917@Github * 【core 】 修复NetUtil.isInRange的cidr判断问题pr#1917@Github
* 【core 】 修复RegexPool中对URL正则匹配问题issue#I4GRKD@Gitee * 【core 】 修复RegexPool中对URL正则匹配问题issue#I4GRKD@Gitee
* 【core 】 修复UrlQuery对于application/x-www-form-urlencoded问题issue#1931@Github
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------

View File

@ -179,6 +179,7 @@ public class PercentCodec implements Serializable {
continue; continue;
} }
// 兼容双字节的Unicode符处理如部分emoji
byte[] ba = buf.toByteArray(); byte[] ba = buf.toByteArray();
for (byte toEncode : ba) { for (byte toEncode : ba) {
// Converting each byte in the buffer // Converting each byte in the buffer

View File

@ -11,15 +11,9 @@ import cn.hutool.core.codec.PercentCodec;
public class FormUrlencoded { public class FormUrlencoded {
/** /**
* query中的value<br> * query中的value默认除"-", "_", ".", "*"外都编码<br>
* value不能包含"{@code &}"可以包含 "=" * 这个类似于JDK提供的{@link java.net.URLEncoder}
*/ */
public static final PercentCodec QUERY_PARAM_VALUE = PercentCodec.of(RFC3986.QUERY_PARAM_VALUE) public static final PercentCodec ALL = PercentCodec.of(RFC3986.UNRESERVED)
.setEncodeSpaceAsPlus(true).removeSafe('+'); .removeSafe('~').addSafe('*').setEncodeSpaceAsPlus(true);
/**
* query中的key<br>
* key不能包含"{@code &}" "="
*/
public static final PercentCodec QUERY_PARAM_NAME = QUERY_PARAM_VALUE.removeSafe('=');
} }

View File

@ -73,7 +73,7 @@ public class RFC3986 {
* query中的key<br> * query中的key<br>
* key不能包含"{@code &}" "=" * key不能包含"{@code &}" "="
*/ */
public static final PercentCodec QUERY_PARAM_NAME = QUERY_PARAM_VALUE.removeSafe('='); public static final PercentCodec QUERY_PARAM_NAME = PercentCodec.of(QUERY_PARAM_VALUE).removeSafe('=');
/** /**
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"

View File

@ -13,6 +13,7 @@ import java.util.BitSet;
/** /**
* URL编码数据内容的类型是 application/x-www-form-urlencoded * URL编码数据内容的类型是 application/x-www-form-urlencoded
* TODO 6.x移除此类使用PercentCodec代替无法很好区分URL编码和www-form编码
* *
* <pre> * <pre>
* 1.字符"a"-"z""A"-"Z""0"-"9"".""-""*""_" 都不会被编码; * 1.字符"a"-"z""A"-"Z""0"-"9"".""-""*""_" 都不会被编码;
@ -21,6 +22,7 @@ import java.util.BitSet;
* </pre> * </pre>
* *
* @author looly * @author looly
* @see cn.hutool.core.codec.PercentCodec
*/ */
public class URLEncoder implements Serializable { public class URLEncoder implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -1,5 +1,6 @@
package cn.hutool.core.net.url; package cn.hutool.core.net.url;
import cn.hutool.core.codec.PercentCodec;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.IterUtil; import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
@ -181,6 +182,24 @@ public class UrlQuery {
* @return URL查询字符串 * @return URL查询字符串
*/ */
public String build(Charset charset) { public String build(Charset charset) {
return build(RFC3986.QUERY_PARAM_NAME, RFC3986.QUERY_PARAM_VALUE, charset);
}
/**
* 构建URL查询字符串即将key-value键值对转换为{@code key1=v1&key2=v2&key3=v3}形式<br>
* 对于{@code null}处理规则如下
* <ul>
* <li>如果key为{@code null}则这个键值对忽略</li>
* <li>如果value为{@code null}只保留key如key1对应value为{@code null}生成类似于{@code key1&key2=v2}形式</li>
* </ul>
*
* @param keyCoder 键值对中键的编码器
* @param valueCoder 键值对中值的编码器
* @param charset encode编码null表示不做encode编码
* @return URL查询字符串
* @since 5.7.16
*/
public String build(PercentCodec keyCoder, PercentCodec valueCoder, Charset charset) {
if (MapUtil.isEmpty(this.query)) { if (MapUtil.isEmpty(this.query)) {
return StrUtil.EMPTY; return StrUtil.EMPTY;
} }
@ -191,13 +210,13 @@ public class UrlQuery {
for (Map.Entry<CharSequence, CharSequence> entry : this.query) { for (Map.Entry<CharSequence, CharSequence> entry : this.query) {
name = entry.getKey(); name = entry.getKey();
if (null != name) { if (null != name) {
if(sb.length() >0){ if (sb.length() > 0) {
sb.append("&"); sb.append("&");
} }
sb.append(RFC3986.QUERY_PARAM_NAME.encode(name, charset)); sb.append(keyCoder.encode(name, charset));
value = entry.getValue(); value = entry.getValue();
if (null != value) { if (null != value) {
sb.append("=").append(RFC3986.QUERY_PARAM_VALUE.encode(value, charset)); sb.append("=").append(valueCoder.encode(value, charset));
} }
} }
} }

View File

@ -0,0 +1,17 @@
package cn.hutool.core.net;
import cn.hutool.core.util.CharsetUtil;
import org.junit.Assert;
import org.junit.Test;
public class FormUrlencodedTest {
@Test
public void encodeParamTest(){
String encode = FormUrlencoded.ALL.encode("a+b", CharsetUtil.CHARSET_UTF_8);
Assert.assertEquals("a%2Bb", encode);
encode = FormUrlencoded.ALL.encode("a b", CharsetUtil.CHARSET_UTF_8);
Assert.assertEquals("a+b", encode);
}
}

View File

@ -0,0 +1,14 @@
package cn.hutool.core.net;
import cn.hutool.core.util.CharsetUtil;
import org.junit.Assert;
import org.junit.Test;
public class RFC3986Test {
@Test
public void encodeQueryTest(){
final String encode = RFC3986.QUERY_PARAM_VALUE.encode("a=b", CharsetUtil.CHARSET_UTF_8);
Assert.assertEquals("a=b", encode);
}
}

View File

@ -1,17 +0,0 @@
package cn.hutool.core.net;
import cn.hutool.core.util.CharsetUtil;
import org.junit.Assert;
import org.junit.Test;
public class URLEncoderTest {
@Test
public void encodeTest(){
String encode = URLEncoder.DEFAULT.encode("+", CharsetUtil.CHARSET_UTF_8);
Assert.assertEquals("+", encode);
encode = URLEncoder.DEFAULT.encode(" ", CharsetUtil.CHARSET_UTF_8);
Assert.assertEquals("%20", encode);
}
}

View File

@ -10,8 +10,10 @@ 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.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
@ -1227,7 +1229,8 @@ public class HttpRequest extends HttpBase<HttpRequest> {
* @since 5.3.2 * @since 5.3.2
*/ */
private String getFormUrlEncoded() { private String getFormUrlEncoded() {
return HttpUtil.toParams(this.form, this.charset); return UrlQuery.of(this.form)
.build(FormUrlencoded.ALL, FormUrlencoded.ALL, this.charset);
} }
/** /**

View File

@ -148,4 +148,5 @@ public class HttpRequestTest {
HttpResponse execute = get.execute(); HttpResponse execute = get.execute();
Console.log(execute.body()); Console.log(execute.body());
} }
} }