mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
add UrlDecoder
This commit is contained in:
@@ -12,11 +12,11 @@ import cn.hutool.core.io.resource.MultiResource;
|
||||
import cn.hutool.core.io.resource.Resource;
|
||||
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.ObjectUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import cn.hutool.http.cookie.GlobalCookieManager;
|
||||
import cn.hutool.http.ssl.SSLSocketFactoryBuilder;
|
||||
|
||||
@@ -96,7 +96,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
GlobalCookieManager.setCookieManager(null);
|
||||
}
|
||||
|
||||
private String url;
|
||||
private UrlBuilder url;
|
||||
private URLStreamHandler urlHandler;
|
||||
private Method method = Method.GET;
|
||||
/**
|
||||
@@ -128,10 +128,6 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
* 是否禁用缓存
|
||||
*/
|
||||
private boolean isDisableCache;
|
||||
/**
|
||||
* 是否对url中的参数进行编码
|
||||
*/
|
||||
private boolean encodeUrlParams;
|
||||
/**
|
||||
* 是否是REST请求模式
|
||||
*/
|
||||
@@ -168,8 +164,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
* @param url URL
|
||||
*/
|
||||
public HttpRequest(String url) {
|
||||
Assert.notBlank(url, "Param [url] can not be blank !");
|
||||
this.url = URLUtil.normalize(url, true);
|
||||
setUrl(url);
|
||||
// 给定一个默认头信息
|
||||
this.header(GlobalHeaders.INSTANCE.headers);
|
||||
}
|
||||
@@ -265,7 +260,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
* @since 4.1.8
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,7 +271,19 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
* @since 4.1.8
|
||||
*/
|
||||
public HttpRequest setUrl(String url) {
|
||||
this.url = url;
|
||||
this.url = UrlBuilder.ofHttp(url, this.charset);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置URL
|
||||
*
|
||||
* @param urlBuilder url字符串
|
||||
* @return this
|
||||
* @since 5.3.1
|
||||
*/
|
||||
public HttpRequest setUrl(UrlBuilder urlBuilder) {
|
||||
this.url = urlBuilder;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -774,9 +781,10 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
* @param isEncodeUrlParams 是否对URL中的参数进行编码
|
||||
* @return this
|
||||
* @since 4.4.1
|
||||
* @deprecated 编码自动完成,无需设置
|
||||
*/
|
||||
@Deprecated
|
||||
public HttpRequest setEncodeUrlParams(boolean isEncodeUrlParams) {
|
||||
this.encodeUrlParams = isEncodeUrlParams;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -925,10 +933,6 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
public HttpResponse execute(boolean isAsync) {
|
||||
// 初始化URL
|
||||
urlWithParamIfGet();
|
||||
// 编码URL
|
||||
if (this.encodeUrlParams) {
|
||||
this.url = HttpUtil.encodeParams(this.url, this.charset);
|
||||
}
|
||||
|
||||
// 初始化 connection
|
||||
initConnection();
|
||||
@@ -982,7 +986,8 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
this.httpConnection.disconnectQuietly();
|
||||
}
|
||||
|
||||
this.httpConnection = HttpConnection.create(URLUtil.toUrlForHttp(this.url, this.urlHandler), this.proxy)//
|
||||
this.httpConnection = HttpConnection
|
||||
.create(this.url.toURL(this.urlHandler), this.proxy)//
|
||||
.setMethod(this.method)//
|
||||
.setHttpsInfo(this.hostnameVerifier, this.ssf)//
|
||||
.setConnectTimeout(this.connectionTimeout)//
|
||||
@@ -1016,9 +1021,9 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
if (Method.GET.equals(method) && false == this.isRest) {
|
||||
// 优先使用body形式的参数,不存在使用form
|
||||
if (ArrayUtil.isNotEmpty(this.bodyBytes)) {
|
||||
this.url = HttpUtil.urlWithForm(this.url, StrUtil.str(this.bodyBytes, this.charset), this.charset, false);
|
||||
this.url.getQuery().parse(StrUtil.str(this.bodyBytes, this.charset), this.charset);
|
||||
} else {
|
||||
this.url = HttpUtil.urlWithForm(this.url, this.form, this.charset, false);
|
||||
this.url.getQuery().addAll(this.form);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1047,7 +1052,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
|
||||
if (responseCode != HttpURLConnection.HTTP_OK) {
|
||||
if (responseCode == HttpURLConnection.HTTP_MOVED_TEMP || responseCode == HttpURLConnection.HTTP_MOVED_PERM || responseCode == HttpURLConnection.HTTP_SEE_OTHER) {
|
||||
this.url = httpConnection.header(Header.LOCATION);
|
||||
setUrl(httpConnection.header(Header.LOCATION));
|
||||
if (redirectCount < this.maxRedirectCount) {
|
||||
redirectCount++;
|
||||
return execute();
|
||||
|
@@ -471,11 +471,11 @@ public class HttpResponse extends HttpBase<HttpResponse> implements Closeable {
|
||||
*/
|
||||
private String getFileNameFromDisposition() {
|
||||
String fileName = null;
|
||||
final String desposition = header(Header.CONTENT_DISPOSITION);
|
||||
if (StrUtil.isNotBlank(desposition)) {
|
||||
fileName = ReUtil.get("filename=\"(.*?)\"", desposition, 1);
|
||||
final String disposition = header(Header.CONTENT_DISPOSITION);
|
||||
if (StrUtil.isNotBlank(disposition)) {
|
||||
fileName = ReUtil.get("filename=\"(.*?)\"", disposition, 1);
|
||||
if (StrUtil.isBlank(fileName)) {
|
||||
fileName = StrUtil.subAfter(desposition, "filename=", true);
|
||||
fileName = StrUtil.subAfter(disposition, "filename=", true);
|
||||
}
|
||||
}
|
||||
return fileName;
|
||||
|
@@ -1,14 +1,12 @@
|
||||
package cn.hutool.http;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.collection.IterUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.io.FastByteArrayOutputStream;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.io.StreamProgress;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.net.url.UrlQuery;
|
||||
import cn.hutool.core.text.StrBuilder;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
@@ -23,13 +21,9 @@ import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@@ -390,44 +384,11 @@ public class HttpUtil {
|
||||
* </pre>
|
||||
*
|
||||
* @param paramMap 表单数据
|
||||
* @param charset 编码
|
||||
* @param charset 编码,null表示不encode键值对
|
||||
* @return url参数
|
||||
*/
|
||||
public static String toParams(Map<String, ?> paramMap, Charset charset) {
|
||||
if (CollectionUtil.isEmpty(paramMap)) {
|
||||
return StrUtil.EMPTY;
|
||||
}
|
||||
if (null == charset) {// 默认编码为系统编码
|
||||
charset = CharsetUtil.CHARSET_UTF_8;
|
||||
}
|
||||
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
boolean isFirst = true;
|
||||
String key;
|
||||
Object value;
|
||||
String valueStr;
|
||||
for (Entry<String, ?> item : paramMap.entrySet()) {
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
} else {
|
||||
sb.append("&");
|
||||
}
|
||||
key = item.getKey();
|
||||
value = item.getValue();
|
||||
if (value instanceof Iterable) {
|
||||
value = CollUtil.join((Iterable<?>) value, ",");
|
||||
} else if (value instanceof Iterator) {
|
||||
value = IterUtil.join((Iterator<?>) value, ",");
|
||||
}
|
||||
valueStr = Convert.toStr(value);
|
||||
if (StrUtil.isNotEmpty(key)) {
|
||||
sb.append(URLUtil.encodeAll(key, charset)).append("=");
|
||||
if (StrUtil.isNotEmpty(valueStr)) {
|
||||
sb.append(URLUtil.encodeAll(valueStr, charset));
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
return URLUtil.buildQuery(paramMap, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -437,7 +398,7 @@ public class HttpUtil {
|
||||
* <p>注意,此方法只能标准化整个URL,并不适合于单独编码参数值</p>
|
||||
*
|
||||
* @param urlWithParams url和参数,可以包含url本身,也可以单独参数
|
||||
* @param charset 编码
|
||||
* @param charset 编码
|
||||
* @return 编码后的url和参数
|
||||
* @since 4.0.1
|
||||
*/
|
||||
@@ -457,10 +418,10 @@ public class HttpUtil {
|
||||
// 无参数,返回url
|
||||
return urlPart;
|
||||
}
|
||||
} else if(false == StrUtil.contains(urlWithParams, '=')){
|
||||
} else if (false == StrUtil.contains(urlWithParams, '=')) {
|
||||
// 无参数的URL
|
||||
return urlWithParams;
|
||||
}else {
|
||||
} else {
|
||||
// 无URL的参数
|
||||
paramPart = urlWithParams;
|
||||
}
|
||||
@@ -536,8 +497,10 @@ public class HttpUtil {
|
||||
* @param charset 字符集
|
||||
* @return 参数Map
|
||||
* @since 4.0.2
|
||||
* @deprecated 请使用 {@link #decodeParamMap(String, Charset)}
|
||||
*/
|
||||
public static HashMap<String, String> decodeParamMap(String paramsStr, String charset) {
|
||||
@Deprecated
|
||||
public static Map<String, String> decodeParamMap(String paramsStr, String charset) {
|
||||
return decodeParamMap(paramsStr, CharsetUtil.charset(charset));
|
||||
}
|
||||
|
||||
@@ -549,15 +512,12 @@ public class HttpUtil {
|
||||
* @return 参数Map
|
||||
* @since 5.2.6
|
||||
*/
|
||||
public static HashMap<String, String> decodeParamMap(String paramsStr, Charset charset) {
|
||||
final Map<String, List<String>> paramsMap = decodeParams(paramsStr, charset);
|
||||
final HashMap<String, String> result = MapUtil.newHashMap(paramsMap.size());
|
||||
List<String> valueList;
|
||||
for (Entry<String, List<String>> entry : paramsMap.entrySet()) {
|
||||
valueList = entry.getValue();
|
||||
result.put(entry.getKey(), CollUtil.isEmpty(valueList) ? null : valueList.get(0));
|
||||
public static Map<String, String> decodeParamMap(String paramsStr, Charset charset) {
|
||||
final Map<CharSequence, CharSequence> queryMap = UrlQuery.of(paramsStr, charset).getQueryMap();
|
||||
if (MapUtil.isEmpty(queryMap)) {
|
||||
return MapUtil.empty();
|
||||
}
|
||||
return result;
|
||||
return Convert.toMap(String.class, String.class, queryMap);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -580,56 +540,17 @@ public class HttpUtil {
|
||||
* @since 5.2.6
|
||||
*/
|
||||
public static Map<String, List<String>> decodeParams(String paramsStr, Charset charset) {
|
||||
if (StrUtil.isBlank(paramsStr)) {
|
||||
return Collections.emptyMap();
|
||||
final Map<CharSequence, CharSequence> queryMap = UrlQuery.of(paramsStr, charset).getQueryMap();
|
||||
if (MapUtil.isEmpty(queryMap)) {
|
||||
return MapUtil.empty();
|
||||
}
|
||||
|
||||
// 去掉Path部分
|
||||
int pathEndPos = paramsStr.indexOf('?');
|
||||
if (pathEndPos > -1) {
|
||||
paramsStr = StrUtil.subSuf(paramsStr, pathEndPos + 1);
|
||||
if (StrUtil.isBlank(paramsStr)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
|
||||
final int len = paramsStr.length();
|
||||
final Map<String, List<String>> params = new LinkedHashMap<>();
|
||||
String name = null;
|
||||
int pos = 0; // 未处理字符开始位置
|
||||
int i; // 未处理字符结束位置
|
||||
char c; // 当前字符
|
||||
for (i = 0; i < len; i++) {
|
||||
c = paramsStr.charAt(i);
|
||||
if (c == '=') { // 键值对的分界点
|
||||
if (null == name) {
|
||||
// name可以是""
|
||||
name = paramsStr.substring(pos, i);
|
||||
}
|
||||
pos = i + 1;
|
||||
} else if (c == '&') { // 参数对的分界点
|
||||
if (null == name && pos != i) {
|
||||
// 对于像&a&这类无参数值的字符串,我们将name为a的值设为""
|
||||
addParam(params, paramsStr.substring(pos, i), StrUtil.EMPTY, charset);
|
||||
} else if (name != null) {
|
||||
addParam(params, name, paramsStr.substring(pos, i), charset);
|
||||
name = null;
|
||||
}
|
||||
pos = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理结尾
|
||||
if (pos != i) {
|
||||
if (name == null) {
|
||||
addParam(params, paramsStr.substring(pos, i), StrUtil.EMPTY, charset);
|
||||
} else {
|
||||
addParam(params, name, paramsStr.substring(pos, i), charset);
|
||||
}
|
||||
} else if (name != null) {
|
||||
addParam(params, name, StrUtil.EMPTY, charset);
|
||||
}
|
||||
|
||||
queryMap.forEach((key, value) -> {
|
||||
final List<String> values = params.computeIfAbsent(StrUtil.str(key), k -> new ArrayList<>(1));
|
||||
// 一般是一个参数
|
||||
values.add(StrUtil.str(value));
|
||||
});
|
||||
return params;
|
||||
}
|
||||
|
||||
@@ -826,26 +747,7 @@ public class HttpUtil {
|
||||
* @return {@link SimpleServer}
|
||||
* @since 5.2.6
|
||||
*/
|
||||
public static SimpleServer createServer(int port){
|
||||
public static SimpleServer createServer(int port) {
|
||||
return new SimpleServer(port);
|
||||
}
|
||||
// ----------------------------------------------------------------------------------------- Private method start
|
||||
|
||||
/**
|
||||
* 将键值对加入到值为List类型的Map中
|
||||
*
|
||||
* @param params 参数
|
||||
* @param name key
|
||||
* @param value value
|
||||
* @param charset 编码
|
||||
*/
|
||||
private static void addParam(Map<String, List<String>> params, String name, String value, Charset charset) {
|
||||
name = URLUtil.decode(name, charset);
|
||||
value = URLUtil.decode(value, charset);
|
||||
final List<String> values = params.computeIfAbsent(name, k -> new ArrayList<>(1));
|
||||
// 一般是一个参数
|
||||
values.add(value);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------- Private method start end
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@ import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -18,7 +19,7 @@ import java.util.Map;
|
||||
public class HttpUtilTest {
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
// @Ignore
|
||||
public void postTest() {
|
||||
String result = HttpUtil.createPost("api.uhaozu.com/goods/description/1120448506").charset(CharsetUtil.UTF_8).execute().body();
|
||||
Console.log(result);
|
||||
@@ -71,6 +72,17 @@ public class HttpUtilTest {
|
||||
Console.log(str);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void getTest5() {
|
||||
String url2 = "http://storage.chancecloud.com.cn/20200413_%E7%B2%A4B12313_386.pdf";
|
||||
ByteArrayOutputStream os2 = new ByteArrayOutputStream();
|
||||
HttpUtil.download(url2, os2, false);
|
||||
|
||||
url2 = "http://storage.chancecloud.com.cn/20200413_粤B12313_386.pdf";
|
||||
HttpUtil.download(url2, os2, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void get12306Test() {
|
||||
|
Reference in New Issue
Block a user