mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-05 17:37:59 +08:00
fix plus encode bug
This commit is contained in:
parent
6b0b729c68
commit
1edbc0de80
CHANGELOG.md
hutool-core/src
main/java/cn/hutool/core
test/java/cn/hutool/core
hutool-http/src/main/java/cn/hutool/http
@ -22,6 +22,7 @@
|
||||
* 【core 】 修复Validator.isUrl()传空返回true(issue#I3ETTY@Gitee)
|
||||
* 【db 】 修复数据库driver根据url的判断识别错误问题(issue#I3EWBI@Gitee)
|
||||
* 【json 】 修复JSONStrFormatter换行多余空行问题(issue#I3FA8B@Gitee)
|
||||
* 【core 】 修复UrlPath中的+被转义为空格%20的问题(issue#1501@Github)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -23,24 +23,84 @@ public class URLDecoder implements Serializable {
|
||||
|
||||
private static final byte ESCAPE_CHAR = '%';
|
||||
|
||||
/**
|
||||
* 解码,不对+解码
|
||||
* <pre>
|
||||
* 1. 将%20转换为空格 ;
|
||||
* 2. 将"%xy"转换为文本形式,xy是两位16进制的数值;
|
||||
* 3. 跳过不符合规范的%形式,直接输出
|
||||
* </pre>
|
||||
*
|
||||
* @param str 包含URL编码后的字符串
|
||||
* @param charset 编码
|
||||
* @return 解码后的字符串
|
||||
*/
|
||||
public static String decodeForPath(String str, Charset charset) {
|
||||
return decode(str, charset, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解码
|
||||
* <pre>
|
||||
* 1. 将+和%20转换为空格 ;
|
||||
* 2. 将"%xy"转换为文本形式,xy是两位16进制的数值;
|
||||
* 3. 跳过不符合规范的%形式,直接输出
|
||||
* </pre>
|
||||
*
|
||||
* @param str 包含URL编码后的字符串
|
||||
* @param charset 编码
|
||||
* @return 解码后的字符串
|
||||
*/
|
||||
public static String decode(String str, Charset charset) {
|
||||
return StrUtil.str(decode(StrUtil.bytes(str, charset)), charset);
|
||||
return decode(str, charset, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解码
|
||||
* <pre>
|
||||
* 1. 将%20转换为空格 ;
|
||||
* 2. 将"%xy"转换为文本形式,xy是两位16进制的数值;
|
||||
* 3. 跳过不符合规范的%形式,直接输出
|
||||
* </pre>
|
||||
*
|
||||
* @param str 包含URL编码后的字符串
|
||||
* @param isPlusToSpace 是否+转换为空格
|
||||
* @param charset 编码
|
||||
* @return 解码后的字符串
|
||||
*/
|
||||
public static String decode(String str, Charset charset, boolean isPlusToSpace) {
|
||||
return StrUtil.str(decode(StrUtil.bytes(str, charset), isPlusToSpace), charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解码
|
||||
* <pre>
|
||||
* 1. 将+和%20转换为空格 ;
|
||||
* 2. 将"%xy"转换为文本形式,xy是两位16进制的数值;
|
||||
* 3. 跳过不符合规范的%形式,直接输出
|
||||
* </pre>
|
||||
*
|
||||
* @param bytes url编码的bytes
|
||||
* @return 解码后的bytes
|
||||
*/
|
||||
public static byte[] decode(byte[] bytes) {
|
||||
return decode(bytes, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解码
|
||||
* <pre>
|
||||
* 1. 将%20转换为空格 ;
|
||||
* 2. 将"%xy"转换为文本形式,xy是两位16进制的数值;
|
||||
* 3. 跳过不符合规范的%形式,直接输出
|
||||
* </pre>
|
||||
*
|
||||
* @param bytes url编码的bytes
|
||||
* @param isPlusToSpace 是否+转换为空格
|
||||
* @return 解码后的bytes
|
||||
* @since 5.6.3
|
||||
*/
|
||||
public static byte[] decode(byte[] bytes, boolean isPlusToSpace) {
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
@ -49,7 +109,7 @@ public class URLDecoder implements Serializable {
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
b = bytes[i];
|
||||
if (b == '+') {
|
||||
buffer.write(CharUtil.SPACE);
|
||||
buffer.write(isPlusToSpace ? CharUtil.SPACE : b);
|
||||
} else if (b == ESCAPE_CHAR) {
|
||||
if (i + 1 < bytes.length) {
|
||||
final int u = CharUtil.digit16(bytes[i + 1]);
|
||||
|
@ -82,6 +82,17 @@ public final class UrlBuilder implements Serializable {
|
||||
return ofHttp(httpUrl, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用URL字符串构建UrlBuilder,当传入的URL没有协议时,按照http协议对待,编码默认使用UTF-8
|
||||
*
|
||||
* @param httpUrl URL字符串
|
||||
* @return UrlBuilder
|
||||
* @since 5.6.3
|
||||
*/
|
||||
public static UrlBuilder ofHttp(String httpUrl) {
|
||||
return ofHttp(httpUrl, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用URL字符串构建UrlBuilder,当传入的URL没有协议时,按照http协议对待。
|
||||
*
|
||||
@ -99,6 +110,16 @@ public final class UrlBuilder implements Serializable {
|
||||
return of(httpUrl, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用URL字符串构建UrlBuilder,默认使用UTF-8编码
|
||||
*
|
||||
* @param url URL字符串
|
||||
* @return UrlBuilder
|
||||
*/
|
||||
public static UrlBuilder of(String url) {
|
||||
return of(url, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用URL字符串构建UrlBuilder
|
||||
*
|
||||
|
@ -2,6 +2,7 @@ package cn.hutool.core.net.url;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.net.URLDecoder;
|
||||
import cn.hutool.core.util.CharUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
@ -97,8 +98,6 @@ public class UrlPath {
|
||||
* @return this
|
||||
*/
|
||||
public UrlPath parse(String path, Charset charset) {
|
||||
UrlPath urlPath = new UrlPath();
|
||||
|
||||
if (StrUtil.isNotEmpty(path)) {
|
||||
// 原URL中以/结尾,则这个规则需保留,issue#I1G44J@Gitee
|
||||
if(StrUtil.endWith(path, CharUtil.SLASH)){
|
||||
@ -108,11 +107,11 @@ public class UrlPath {
|
||||
path = fixPath(path);
|
||||
final List<String> split = StrUtil.split(path, '/');
|
||||
for (String seg : split) {
|
||||
addInternal(URLUtil.decode(seg, charset), false);
|
||||
addInternal(URLDecoder.decodeForPath(seg, charset), false);
|
||||
}
|
||||
}
|
||||
|
||||
return urlPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,7 +134,7 @@ public class URLUtil {
|
||||
* @return URL
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static URI getStringURI(CharSequence content){
|
||||
public static URI getStringURI(CharSequence content) {
|
||||
final String contentStr = StrUtil.addPrefixIfNot(content, "string:///");
|
||||
return URI.create(contentStr);
|
||||
}
|
||||
@ -467,6 +467,23 @@ public class URLUtil {
|
||||
return URLDecoder.decode(content, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解码application/x-www-form-urlencoded字符<br>
|
||||
* 将%开头的16进制表示的内容解码。
|
||||
*
|
||||
* @param content 被解码内容
|
||||
* @param charset 编码,null表示不解码
|
||||
* @param isPlusToSpace 是否+转换为空格
|
||||
* @return 编码后的字符
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解码application/x-www-form-urlencoded字符<br>
|
||||
* 将%开头的16进制表示的内容解码。
|
||||
@ -705,7 +722,7 @@ public class URLUtil {
|
||||
*
|
||||
* @param url URL字符串
|
||||
* @param isEncodePath 是否对URL中path部分的中文和特殊字符做转义(不包括 http:, /和域名部分)
|
||||
* @param replaceSlash 是否替换url body中的 //
|
||||
* @param replaceSlash 是否替换url body中的 //
|
||||
* @return 标准化后的URL字符串
|
||||
* @since 5.5.5
|
||||
*/
|
||||
|
@ -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 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);
|
||||
}
|
||||
}
|
@ -18,6 +18,13 @@ public class UrlBuilderTest {
|
||||
Assert.assertEquals("http://www.hutool.cn/", buildUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildTest2() {
|
||||
// path中的+不做处理
|
||||
String buildUrl = UrlBuilder.ofHttp("http://www.hutool.cn/+8618888888888", CharsetUtil.CHARSET_UTF_8).build();
|
||||
Assert.assertEquals("http://www.hutool.cn/+8618888888888", buildUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHost() {
|
||||
String buildUrl = UrlBuilder.create()
|
||||
|
@ -0,0 +1,12 @@
|
||||
package cn.hutool.core.net;
|
||||
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class UrlDecoderTest {
|
||||
@Test
|
||||
public void decodeForPathTest(){
|
||||
Assert.assertEquals("+", URLDecoder.decodeForPath("+", CharsetUtil.CHARSET_UTF_8));
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@ import java.net.URL;
|
||||
|
||||
/**
|
||||
* URLUtil单元测试
|
||||
*
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
@ -26,24 +26,24 @@ public class URLUtilTest {
|
||||
normalize = URLUtil.normalize(url);
|
||||
Assert.assertEquals("http://www.hutool.cn//aaa/bbb", normalize);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void normalizeTest2() {
|
||||
String url = "http://www.hutool.cn//aaa/\\bbb?a=1&b=2";
|
||||
String normalize = URLUtil.normalize(url);
|
||||
Assert.assertEquals("http://www.hutool.cn//aaa//bbb?a=1&b=2", normalize);
|
||||
|
||||
|
||||
url = "www.hutool.cn//aaa/bbb?a=1&b=2";
|
||||
normalize = URLUtil.normalize(url);
|
||||
Assert.assertEquals("http://www.hutool.cn//aaa/bbb?a=1&b=2", normalize);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void normalizeTest3() {
|
||||
String url = "http://www.hutool.cn//aaa/\\bbb?a=1&b=2";
|
||||
String normalize = URLUtil.normalize(url, true);
|
||||
Assert.assertEquals("http://www.hutool.cn//aaa//bbb?a=1&b=2", normalize);
|
||||
|
||||
|
||||
url = "www.hutool.cn//aaa/bbb?a=1&b=2";
|
||||
normalize = URLUtil.normalize(url, true);
|
||||
Assert.assertEquals("http://www.hutool.cn//aaa/bbb?a=1&b=2", normalize);
|
||||
@ -59,7 +59,7 @@ public class URLUtilTest {
|
||||
String normalize = URLUtil.normalize("http://[fe80::8f8:2022:a603:d180]:9439", true);
|
||||
Assert.assertEquals(url, normalize);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void formatTest() {
|
||||
String url = "//www.hutool.cn//aaa/\\bbb?a=1&b=2";
|
||||
@ -81,7 +81,7 @@ public class URLUtilTest {
|
||||
String encode = URLUtil.encode(body);
|
||||
Assert.assertEquals("366466%20-%20%E5%89%AF%E6%9C%AC.jpg", encode);
|
||||
Assert.assertEquals(body, URLUtil.decode(encode));
|
||||
|
||||
|
||||
String encode2 = URLUtil.encodeQuery(body);
|
||||
Assert.assertEquals("366466+-+%E5%89%AF%E6%9C%AC.jpg", encode2);
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ public enum ContentType {
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为默认Content-Type,默认包括<code>null</code>和application/x-www-form-urlencoded
|
||||
* 是否为默认Content-Type,默认包括{@code null}和application/x-www-form-urlencoded
|
||||
*
|
||||
* @param contentType 内容类型
|
||||
* @return 是否为默认Content-Type
|
||||
|
@ -12,7 +12,6 @@ import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
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.MultipartBody;
|
||||
@ -157,7 +156,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
* @param url URL
|
||||
*/
|
||||
public HttpRequest(String url) {
|
||||
this(UrlBuilder.ofHttp(url, CharsetUtil.CHARSET_UTF_8));
|
||||
this(UrlBuilder.ofHttp(url));
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user