This commit is contained in:
Looly 2023-04-17 12:24:49 +08:00
parent 30e91dd505
commit d2fd9d448d
26 changed files with 137 additions and 106 deletions

View File

@ -66,7 +66,7 @@ public class CollectionValueMap<K, V> extends AbsCollValueMap<K, V> {
} }
/** /**
* 创建一个多值映射集合默认基于{@link HashMap}{@link ArrayList}实现 * 创建一个多值映射集合默认基于指定Map与指定List类型实现
* *
* @param map 提供数据的原始集合 * @param map 提供数据的原始集合
*/ */

View File

@ -39,7 +39,7 @@ public class ListValueMap<K, V> extends AbsCollValueMap<K, V> {
} }
/** /**
* 基于{@link HashMap}创建一个值为{@link List}的多值映射集合 * 基于指定Map创建一个值为{@link List}的多值映射集合
* *
* @param map 提供数据的原始集合 * @param map 提供数据的原始集合
*/ */

View File

@ -16,7 +16,8 @@ import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSession;
/** /**
* https 域名校验信任所有域名 * https 域名校验信任所有域名<br>
* 注意此类慎用信任全部可能会有中间人攻击风险
* *
* @author Looly * @author Looly
*/ */

View File

@ -22,6 +22,8 @@ import java.security.cert.X509Certificate;
* 继承{@link X509ExtendedTrustManager}的原因见<br> * 继承{@link X509ExtendedTrustManager}的原因见<br>
* https://blog.csdn.net/ghaohao/article/details/79454913 * https://blog.csdn.net/ghaohao/article/details/79454913
* *
* <p>注意此类慎用信任全部可能会有中间人攻击风险</p>
*
* @author Looly * @author Looly
* @since 5.5.7 * @since 5.5.7
*/ */

View File

@ -109,6 +109,12 @@
<artifactId>mockwebserver</artifactId> <artifactId>mockwebserver</artifactId>
<version>4.10.0</version> <version>4.10.0</version>
<scope>test</scope> <scope>test</scope>
<exclusions>
<exclusion>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
</exclusion>
</exclusions>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -15,7 +15,7 @@ package org.dromara.hutool.http;
import org.dromara.hutool.core.collection.CollUtil; import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.http.meta.Header; import org.dromara.hutool.http.meta.HeaderName;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -69,12 +69,12 @@ public enum GlobalHeaders {
//header(Header.ACCEPT, "text/html,application/json,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", true); //header(Header.ACCEPT, "text/html,application/json,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", true);
// 某些请求中这个自定义头会导致请求失败此处采用与PostMan一致的默认头 // 某些请求中这个自定义头会导致请求失败此处采用与PostMan一致的默认头
header(Header.ACCEPT, "*/*", true); header(HeaderName.ACCEPT, "*/*", true);
header(Header.ACCEPT_ENCODING, "gzip, deflate", true); header(HeaderName.ACCEPT_ENCODING, "gzip, deflate", true);
header(Header.ACCEPT_LANGUAGE, "zh-CN,zh;q=0.8", true); header(HeaderName.ACCEPT_LANGUAGE, "zh-CN,zh;q=0.8", true);
// 此Header只有在post请求中有用因此在HttpRequest的method方法中设置此头信息此处去掉 // 此Header只有在post请求中有用因此在HttpRequest的method方法中设置此头信息此处去掉
// header(Header.CONTENT_TYPE, ContentType.FORM_URLENCODED.toString(CharsetUtil.CHARSET_UTF_8), true); // header(Header.CONTENT_TYPE, ContentType.FORM_URLENCODED.toString(CharsetUtil.CHARSET_UTF_8), true);
header(Header.USER_AGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36 Hutool", true); header(HeaderName.USER_AGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36 Hutool", true);
return this; return this;
} }
@ -115,7 +115,7 @@ public enum GlobalHeaders {
* @param name Header名 * @param name Header名
* @return Header值 * @return Header值
*/ */
public String header(final Header name) { public String header(final HeaderName name) {
if (null == name) { if (null == name) {
return null; return null;
} }
@ -154,7 +154,7 @@ public enum GlobalHeaders {
* @param isOverride 是否覆盖已有值 * @param isOverride 是否覆盖已有值
* @return this * @return this
*/ */
public GlobalHeaders header(final Header name, final String value, final boolean isOverride) { public GlobalHeaders header(final HeaderName name, final String value, final boolean isOverride) {
return header(name.toString(), value, isOverride); return header(name.toString(), value, isOverride);
} }
@ -166,7 +166,7 @@ public enum GlobalHeaders {
* @param value Header值 * @param value Header值
* @return this * @return this
*/ */
public GlobalHeaders header(final Header name, final String value) { public GlobalHeaders header(final HeaderName name, final String value) {
return header(name.toString(), value, true); return header(name.toString(), value, true);
} }
@ -223,7 +223,7 @@ public enum GlobalHeaders {
* @param name Header名 * @param name Header名
* @return this * @return this
*/ */
public GlobalHeaders removeHeader(final Header name) { public GlobalHeaders removeHeader(final HeaderName name) {
return removeHeader(name.toString()); return removeHeader(name.toString());
} }

View File

@ -24,6 +24,7 @@ public interface ClientEngine extends Closeable {
/** /**
* 设置客户端引擎参数如超时代理等信息 * 设置客户端引擎参数如超时代理等信息
*
* @param config 客户端设置 * @param config 客户端设置
* @return this * @return this
*/ */
@ -31,6 +32,7 @@ public interface ClientEngine extends Closeable {
/** /**
* 发送HTTP请求 * 发送HTTP请求
*
* @param message HTTP请求消息 * @param message HTTP请求消息
* @return 响应内容 * @return 响应内容
*/ */

View File

@ -12,15 +12,14 @@
package org.dromara.hutool.http.client; package org.dromara.hutool.http.client;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.collection.CollUtil; import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.array.ArrayUtil; import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.meta.Header;
import java.net.HttpCookie; import java.net.HttpCookie;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@ -38,7 +37,7 @@ public interface HeaderOperation<T extends HeaderOperation<T>> {
* *
* @return Headers Map * @return Headers Map
*/ */
Map<String, List<String>> headers(); Map<String, ? extends Collection<String>> headers();
/** /**
* 设置一个header<br> * 设置一个header<br>
@ -55,11 +54,11 @@ public interface HeaderOperation<T extends HeaderOperation<T>> {
/** /**
* 获取指定的Header值如果不存在返回{@code null} * 获取指定的Header值如果不存在返回{@code null}
* *
* @param header header名 * @param headerName header名
* @return header值 * @return header值
*/ */
default String header(final Header header) { default String header(final HeaderName headerName) {
return header(header.getValue()); return header(headerName.getValue());
} }
/** /**
@ -69,9 +68,9 @@ public interface HeaderOperation<T extends HeaderOperation<T>> {
* @return header值 * @return header值
*/ */
default String header(final String name) { default String header(final String name) {
final List<String> values = headers().get(name); final Collection<String> values = headers().get(name);
if (ArrayUtil.isNotEmpty(values)) { if (ArrayUtil.isNotEmpty(values)) {
return values.get(0); return CollUtil.getFirst(values);
} }
return null; return null;
@ -86,7 +85,7 @@ public interface HeaderOperation<T extends HeaderOperation<T>> {
* @param isOverride 是否覆盖已有值 * @param isOverride 是否覆盖已有值
* @return T 本身 * @return T 本身
*/ */
default T header(final Header name, final String value, final boolean isOverride) { default T header(final HeaderName name, final String value, final boolean isOverride) {
return header(name.toString(), value, isOverride); return header(name.toString(), value, isOverride);
} }
@ -98,7 +97,7 @@ public interface HeaderOperation<T extends HeaderOperation<T>> {
* @param value Header值 * @param value Header值
* @return T 本身 * @return T 本身
*/ */
default T header(final Header name, final String value) { default T header(final HeaderName name, final String value) {
return header(name.toString(), value, true); return header(name.toString(), value, true);
} }
@ -121,10 +120,10 @@ public interface HeaderOperation<T extends HeaderOperation<T>> {
* @param isOverride 是否覆盖 * @param isOverride 是否覆盖
* @return this * @return this
*/ */
default T header(final Map<String, List<String>> headerMap, final boolean isOverride) { default T header(final Map<String, ? extends Collection<String>> headerMap, final boolean isOverride) {
if (MapUtil.isNotEmpty(headerMap)) { if (MapUtil.isNotEmpty(headerMap)) {
String name; String name;
for (final Map.Entry<String, List<String>> entry : headerMap.entrySet()) { for (final Map.Entry<String, ? extends Collection<String>> entry : headerMap.entrySet()) {
name = entry.getKey(); name = entry.getKey();
for (final String value : entry.getValue()) { for (final String value : entry.getValue()) {
this.header(name, StrUtil.emptyIfNull(value), isOverride); this.header(name, StrUtil.emptyIfNull(value), isOverride);
@ -141,7 +140,7 @@ public interface HeaderOperation<T extends HeaderOperation<T>> {
* @return T * @return T
*/ */
default T contentType(final String contentType) { default T contentType(final String contentType) {
header(Header.CONTENT_TYPE, contentType); header(HeaderName.CONTENT_TYPE, contentType);
return (T) this; return (T) this;
} }
@ -152,7 +151,7 @@ public interface HeaderOperation<T extends HeaderOperation<T>> {
* @return T * @return T
*/ */
default T keepAlive(final boolean isKeepAlive) { default T keepAlive(final boolean isKeepAlive) {
header(Header.CONNECTION, isKeepAlive ? "Keep-Alive" : "Close"); header(HeaderName.CONNECTION, isKeepAlive ? "Keep-Alive" : "Close");
return (T) this; return (T) this;
} }
@ -177,7 +176,7 @@ public interface HeaderOperation<T extends HeaderOperation<T>> {
* @return T this * @return T this
*/ */
default T auth(final String content) { default T auth(final String content) {
header(Header.AUTHORIZATION, content, true); header(HeaderName.AUTHORIZATION, content, true);
return (T) this; return (T) this;
} }
@ -188,7 +187,7 @@ public interface HeaderOperation<T extends HeaderOperation<T>> {
* @return T this * @return T this
*/ */
default T proxyAuth(final String content) { default T proxyAuth(final String content) {
header(Header.PROXY_AUTHORIZATION, content, true); header(HeaderName.PROXY_AUTHORIZATION, content, true);
return (T) this; return (T) this;
} }
@ -233,7 +232,7 @@ public interface HeaderOperation<T extends HeaderOperation<T>> {
* @since 3.0.7 * @since 3.0.7
*/ */
default T cookie(final String cookie) { default T cookie(final String cookie) {
return header(Header.COOKIE, cookie, true); return header(HeaderName.COOKIE, cookie, true);
} }
/** /**

View File

@ -12,10 +12,10 @@
package org.dromara.hutool.http.client; package org.dromara.hutool.http.client;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.collection.ListUtil; import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.map.multi.ListValueMap;
import org.dromara.hutool.core.net.url.UrlBuilder; import org.dromara.hutool.core.net.url.UrlBuilder;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.CharsetUtil; import org.dromara.hutool.core.util.CharsetUtil;
@ -26,12 +26,12 @@ import org.dromara.hutool.http.HttpUtil;
import org.dromara.hutool.http.client.body.HttpBody; import org.dromara.hutool.http.client.body.HttpBody;
import org.dromara.hutool.http.client.body.StringBody; import org.dromara.hutool.http.client.body.StringBody;
import org.dromara.hutool.http.client.body.UrlEncodedFormBody; import org.dromara.hutool.http.client.body.UrlEncodedFormBody;
import org.dromara.hutool.http.meta.Header; import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.meta.Method; import org.dromara.hutool.http.meta.Method;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.HashMap; import java.util.Collection;
import java.util.List; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
/** /**
@ -95,7 +95,7 @@ public class Request implements HeaderOperation<Request> {
/** /**
* 存储头信息 * 存储头信息
*/ */
private final Map<String, List<String>> headers; private final ListValueMap<String, String> headers;
/** /**
* 请求体 * 请求体
*/ */
@ -110,7 +110,7 @@ public class Request implements HeaderOperation<Request> {
*/ */
public Request() { public Request() {
method = Method.GET; method = Method.GET;
headers = new HashMap<>(); headers = new ListValueMap<>(new LinkedHashMap<>());
maxRedirectCount = HttpGlobalConfig.getMaxRedirectCount(); maxRedirectCount = HttpGlobalConfig.getMaxRedirectCount();
// 全局默认请求头 // 全局默认请求头
@ -181,7 +181,7 @@ public class Request implements HeaderOperation<Request> {
} }
@Override @Override
public Map<String, List<String>> headers() { public Map<String, ? extends Collection<String>> headers() {
return MapUtil.view(this.headers); return MapUtil.view(this.headers);
} }
@ -191,7 +191,7 @@ public class Request implements HeaderOperation<Request> {
* @return 是否为Transfer-Encoding:Chunked的内容 * @return 是否为Transfer-Encoding:Chunked的内容
*/ */
public boolean isChunked() { public boolean isChunked() {
final String transferEncoding = header(Header.TRANSFER_ENCODING); final String transferEncoding = header(HeaderName.TRANSFER_ENCODING);
return "Chunked".equalsIgnoreCase(transferEncoding); return "Chunked".equalsIgnoreCase(transferEncoding);
} }
@ -215,11 +215,10 @@ public class Request implements HeaderOperation<Request> {
return this; return this;
} }
final List<String> values = headers.get(name.trim()); if (isOverride) {
if (isOverride || CollUtil.isEmpty(values)) { this.headers.put(name.trim(), ListUtil.of(value));
headers.put(name.trim(), ListUtil.of(value));
} else { } else {
values.add(value.trim()); this.headers.putValue(name.trim(), value);
} }
return this; return this;
} }
@ -263,8 +262,8 @@ public class Request implements HeaderOperation<Request> {
this.body = body; this.body = body;
// 根据内容赋值默认Content-Type // 根据内容赋值默认Content-Type
if (StrUtil.isBlank(header(Header.CONTENT_TYPE))) { if (StrUtil.isBlank(header(HeaderName.CONTENT_TYPE))) {
header(Header.CONTENT_TYPE, body.getContentType(charset()), true); header(HeaderName.CONTENT_TYPE, body.getContentType(charset()), true);
} }
return this; return this;

View File

@ -18,7 +18,7 @@ import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.http.HttpException; import org.dromara.hutool.http.HttpException;
import org.dromara.hutool.http.client.body.ResponseBody; import org.dromara.hutool.http.client.body.ResponseBody;
import org.dromara.hutool.http.meta.ContentTypeUtil; import org.dromara.hutool.http.meta.ContentTypeUtil;
import org.dromara.hutool.http.meta.Header; import org.dromara.hutool.http.meta.HeaderName;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
@ -65,7 +65,7 @@ public interface Response extends Closeable {
* @return 字符集 * @return 字符集
*/ */
default Charset charset() { default Charset charset() {
return ContentTypeUtil.getCharset(header(Header.CONTENT_TYPE)); return ContentTypeUtil.getCharset(header(HeaderName.CONTENT_TYPE));
} }
/** /**
@ -129,7 +129,7 @@ public interface Response extends Closeable {
* @param name Header名 * @param name Header名
* @return Header值 * @return Header值
*/ */
default String header(final Header name) { default String header(final HeaderName name) {
if (null == name) { if (null == name) {
return null; return null;
} }
@ -142,7 +142,7 @@ public interface Response extends Closeable {
* @return String * @return String
*/ */
default String contentEncoding() { default String contentEncoding() {
return header(Header.CONTENT_ENCODING); return header(HeaderName.CONTENT_ENCODING);
} }
/** /**
@ -157,7 +157,7 @@ public interface Response extends Closeable {
* @since 5.7.9 * @since 5.7.9
*/ */
default long contentLength() { default long contentLength() {
long contentLength = Convert.toLong(header(Header.CONTENT_LENGTH), -1L); long contentLength = Convert.toLong(header(HeaderName.CONTENT_LENGTH), -1L);
if (contentLength > 0 && (isChunked() || StrUtil.isNotBlank(contentEncoding()))) { if (contentLength > 0 && (isChunked() || StrUtil.isNotBlank(contentEncoding()))) {
//按照HTTP协议规范 Transfer-Encoding和Content-Encoding设置后 Content-Length 无效 //按照HTTP协议规范 Transfer-Encoding和Content-Encoding设置后 Content-Length 无效
contentLength = -1; contentLength = -1;
@ -172,7 +172,7 @@ public interface Response extends Closeable {
* @since 4.6.2 * @since 4.6.2
*/ */
default boolean isChunked() { default boolean isChunked() {
final String transferEncoding = header(Header.TRANSFER_ENCODING); final String transferEncoding = header(HeaderName.TRANSFER_ENCODING);
return "Chunked".equalsIgnoreCase(transferEncoding); return "Chunked".equalsIgnoreCase(transferEncoding);
} }
@ -183,7 +183,7 @@ public interface Response extends Closeable {
* @since 3.1.1 * @since 3.1.1
*/ */
default String getCookieStr() { default String getCookieStr() {
return header(Header.SET_COOKIE); return header(HeaderName.SET_COOKIE);
} }
/** /**

View File

@ -24,7 +24,7 @@ import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.http.HttpException; import org.dromara.hutool.http.HttpException;
import org.dromara.hutool.http.client.Response; import org.dromara.hutool.http.client.Response;
import org.dromara.hutool.http.html.HtmlUtil; import org.dromara.hutool.http.html.HtmlUtil;
import org.dromara.hutool.http.meta.Header; import org.dromara.hutool.http.meta.HeaderName;
import java.io.Closeable; import java.io.Closeable;
import java.io.File; import java.io.File;
@ -60,7 +60,7 @@ public class ResponseBody implements HttpBody, Closeable {
@Override @Override
public String getContentType() { public String getContentType() {
return response.header(Header.CONTENT_TYPE); return response.header(HeaderName.CONTENT_TYPE);
} }
@Override @Override
@ -249,7 +249,7 @@ public class ResponseBody implements HttpBody, Closeable {
*/ */
private String getFileNameFromDisposition(final String paramName) { private String getFileNameFromDisposition(final String paramName) {
String fileName = null; String fileName = null;
final String disposition = response.header(Header.CONTENT_DISPOSITION); final String disposition = response.header(HeaderName.CONTENT_DISPOSITION);
if (StrUtil.isNotBlank(disposition)) { if (StrUtil.isNotBlank(disposition)) {
fileName = ReUtil.get(paramName + "=\"(.*?)\"", disposition, 1); fileName = ReUtil.get(paramName + "=\"(.*?)\"", disposition, 1);
if (StrUtil.isBlank(fileName)) { if (StrUtil.isBlank(fileName)) {

View File

@ -22,6 +22,7 @@ import org.dromara.hutool.http.client.ClientEngine;
import org.dromara.hutool.http.client.Request; import org.dromara.hutool.http.client.Request;
import org.dromara.hutool.http.client.Response; import org.dromara.hutool.http.client.Response;
import org.dromara.hutool.http.client.body.HttpBody; import org.dromara.hutool.http.client.body.HttpBody;
import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.ssl.SSLInfo; import org.dromara.hutool.http.ssl.SSLInfo;
import org.apache.http.Header; import org.apache.http.Header;
import org.apache.http.client.config.RequestConfig; import org.apache.http.client.config.RequestConfig;
@ -36,6 +37,7 @@ import org.apache.http.message.BasicHeader;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -142,7 +144,7 @@ public class HttpClient4Engine implements ClientEngine {
final HttpBody body = message.body(); final HttpBody body = message.body();
request.setEntity(new HttpClient4BodyEntity( request.setEntity(new HttpClient4BodyEntity(
// 用户自定义的内容类型 // 用户自定义的内容类型
message.header(org.dromara.hutool.http.meta.Header.CONTENT_TYPE), message.header(HeaderName.CONTENT_TYPE),
// 用户自定义编码 // 用户自定义编码
message.charset(), message.charset(),
message.isChunked(), message.isChunked(),
@ -156,7 +158,7 @@ public class HttpClient4Engine implements ClientEngine {
* *
* @return 默认头列表 * @return 默认头列表
*/ */
private static List<Header> toHeaderList(final Map<String, List<String>> headersMap) { private static List<Header> toHeaderList(final Map<String, ? extends Collection<String>> headersMap) {
final List<Header> result = new ArrayList<>(); final List<Header> result = new ArrayList<>();
headersMap.forEach((k, v1) -> v1.forEach((v2) -> result.add(new BasicHeader(k, v2)))); headersMap.forEach((k, v1) -> v1.forEach((v2) -> result.add(new BasicHeader(k, v2))));
return result; return result;

View File

@ -22,6 +22,7 @@ import org.dromara.hutool.http.client.ClientEngine;
import org.dromara.hutool.http.client.Request; import org.dromara.hutool.http.client.Request;
import org.dromara.hutool.http.client.Response; import org.dromara.hutool.http.client.Response;
import org.dromara.hutool.http.client.body.HttpBody; import org.dromara.hutool.http.client.body.HttpBody;
import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.ssl.SSLInfo; import org.dromara.hutool.http.ssl.SSLInfo;
import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase; import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase;
import org.apache.hc.client5.http.config.ConnectionConfig; import org.apache.hc.client5.http.config.ConnectionConfig;
@ -40,6 +41,7 @@ import org.apache.hc.core5.http.message.BasicHeader;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -140,7 +142,7 @@ public class HttpClient5Engine implements ClientEngine {
final HttpBody body = message.body(); final HttpBody body = message.body();
request.setEntity(new HttpClient5BodyEntity( request.setEntity(new HttpClient5BodyEntity(
// 用户自定义的内容类型 // 用户自定义的内容类型
message.header(org.dromara.hutool.http.meta.Header.CONTENT_TYPE), message.header(HeaderName.CONTENT_TYPE),
// 用户自定义编码 // 用户自定义编码
message.charset(), message.charset(),
message.isChunked(), message.isChunked(),
@ -154,7 +156,7 @@ public class HttpClient5Engine implements ClientEngine {
* *
* @return 默认头列表 * @return 默认头列表
*/ */
private static List<Header> toHeaderList(final Map<String, List<String>> headersMap) { private static List<Header> toHeaderList(final Map<String, ? extends Collection<String>> headersMap) {
final List<Header> result = new ArrayList<>(); final List<Header> result = new ArrayList<>();
headersMap.forEach((k, v1) -> v1.forEach((v2) -> result.add(new BasicHeader(k, v2)))); headersMap.forEach((k, v1) -> v1.forEach((v2) -> result.add(new BasicHeader(k, v2))));
return result; return result;

View File

@ -24,7 +24,7 @@ import org.dromara.hutool.http.client.Request;
import org.dromara.hutool.http.client.Response; import org.dromara.hutool.http.client.Response;
import org.dromara.hutool.http.client.body.HttpBody; import org.dromara.hutool.http.client.body.HttpBody;
import org.dromara.hutool.http.client.cookie.GlobalCookieManager; import org.dromara.hutool.http.client.cookie.GlobalCookieManager;
import org.dromara.hutool.http.meta.Header; import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.meta.HttpStatus; import org.dromara.hutool.http.meta.HttpStatus;
import org.dromara.hutool.http.meta.Method; import org.dromara.hutool.http.meta.Method;
@ -149,7 +149,7 @@ public class JdkClientEngine implements ClientEngine {
// 覆盖默认Header // 覆盖默认Header
.header(message.headers(), true); .header(message.headers(), true);
if (null == message.header(Header.COOKIE)) { if (null == message.header(HeaderName.COOKIE)) {
// 用户没有自定义Cookie则读取全局Cookie信息并附带到请求中 // 用户没有自定义Cookie则读取全局Cookie信息并附带到请求中
GlobalCookieManager.add(conn); GlobalCookieManager.add(conn);
} }
@ -178,7 +178,7 @@ public class JdkClientEngine implements ClientEngine {
if (code != HttpURLConnection.HTTP_OK) { if (code != HttpURLConnection.HTTP_OK) {
if (HttpStatus.isRedirected(code)) { if (HttpStatus.isRedirected(code)) {
message.url(getLocationUrl(message.url(), conn.header(Header.LOCATION))); message.url(getLocationUrl(message.url(), conn.header(HeaderName.LOCATION)));
if (redirectCount < message.maxRedirectCount()) { if (redirectCount < message.maxRedirectCount()) {
redirectCount++; redirectCount++;
return send(message, isAsync); return send(message, isAsync);

View File

@ -13,11 +13,11 @@
package org.dromara.hutool.http.meta; package org.dromara.hutool.http.meta;
/** /**
* Http 头域 * Http头名称枚举
* *
* @author Looly * @author Looly
*/ */
public enum Header { public enum HeaderName {
//------------------------------------------------------------- 通用头域 //------------------------------------------------------------- 通用头域
/** /**
@ -145,7 +145,7 @@ public enum Header {
private final String value; private final String value;
Header(final String value) { HeaderName(final String value) {
this.value = value; this.value = value;
} }
@ -154,7 +154,7 @@ public enum Header {
* *
* @return * @return
*/ */
public String getValue(){ public String getValue() {
return this.value; return this.value;
} }

View File

@ -0,0 +1,18 @@
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* HTTP代理相关封装
*
* @author looly
*/
package org.dromara.hutool.http.proxy;

View File

@ -26,7 +26,7 @@ import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.util.CharsetUtil; import org.dromara.hutool.core.util.CharsetUtil;
import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.http.meta.ContentTypeUtil; import org.dromara.hutool.http.meta.ContentTypeUtil;
import org.dromara.hutool.http.meta.Header; import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.meta.Method; import org.dromara.hutool.http.meta.Method;
import org.dromara.hutool.http.useragent.UserAgent; import org.dromara.hutool.http.useragent.UserAgent;
import org.dromara.hutool.http.useragent.UserAgentUtil; import org.dromara.hutool.http.useragent.UserAgentUtil;
@ -130,11 +130,11 @@ public class HttpServerRequest extends HttpServerBase {
/** /**
* 获得请求header中的信息 * 获得请求header中的信息
* *
* @param headerKey 头信息的KEY * @param headerNameKey 头信息的KEY
* @return header值 * @return header值
*/ */
public String getHeader(final Header headerKey) { public String getHeader(final HeaderName headerNameKey) {
return getHeader(headerKey.toString()); return getHeader(headerNameKey.toString());
} }
/** /**
@ -168,7 +168,7 @@ public class HttpServerRequest extends HttpServerBase {
* @return Content-Type头信息 * @return Content-Type头信息
*/ */
public String getContentType() { public String getContentType() {
return getHeader(Header.CONTENT_TYPE); return getHeader(HeaderName.CONTENT_TYPE);
} }
/** /**
@ -195,7 +195,7 @@ public class HttpServerRequest extends HttpServerBase {
* @return User-Agent字符串 * @return User-Agent字符串
*/ */
public String getUserAgentStr() { public String getUserAgentStr() {
return getHeader(Header.USER_AGENT); return getHeader(HeaderName.USER_AGENT);
} }
/** /**
@ -213,7 +213,7 @@ public class HttpServerRequest extends HttpServerBase {
* @return cookie字符串 * @return cookie字符串
*/ */
public String getCookiesStr() { public String getCookiesStr() {
return getHeader(Header.COOKIE); return getHeader(HeaderName.COOKIE);
} }
/** /**

View File

@ -20,7 +20,7 @@ import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ByteUtil; import org.dromara.hutool.core.util.ByteUtil;
import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.http.meta.ContentType; import org.dromara.hutool.http.meta.ContentType;
import org.dromara.hutool.http.meta.Header; import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.meta.HttpStatus; import org.dromara.hutool.http.meta.HttpStatus;
import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpExchange;
@ -150,12 +150,12 @@ public class HttpServerResponse extends HttpServerBase {
/** /**
* 设置响应头如果已经存在则覆盖 * 设置响应头如果已经存在则覆盖
* *
* @param header 头key * @param headerName 头key
* @param value * @param value
* @return this * @return this
*/ */
public HttpServerResponse setHeader(final Header header, final String value) { public HttpServerResponse setHeader(final HeaderName headerName, final String value) {
return setHeader(header.getValue(), value); return setHeader(headerName.getValue(), value);
} }
/** /**
@ -207,7 +207,7 @@ public class HttpServerResponse extends HttpServerBase {
} }
} }
return setHeader(Header.CONTENT_TYPE, contentType); return setHeader(HeaderName.CONTENT_TYPE, contentType);
} }
/** /**
@ -217,7 +217,7 @@ public class HttpServerResponse extends HttpServerBase {
* @return this * @return this
*/ */
public HttpServerResponse setContentLength(final long contentLength) { public HttpServerResponse setContentLength(final long contentLength) {
return setHeader(Header.CONTENT_LENGTH, String.valueOf(contentLength)); return setHeader(HeaderName.CONTENT_LENGTH, String.valueOf(contentLength));
} }
/** /**
@ -435,7 +435,7 @@ public class HttpServerResponse extends HttpServerBase {
if (!contentType.startsWith("text/")) { if (!contentType.startsWith("text/")) {
// 非文本类型数据直接走下载 // 非文本类型数据直接走下载
setHeader(Header.CONTENT_DISPOSITION, StrUtil.format("attachment;filename={}", URLEncoder.encodeAll(fileName, charset))); setHeader(HeaderName.CONTENT_DISPOSITION, StrUtil.format("attachment;filename={}", URLEncoder.encodeAll(fileName, charset)));
} }
return write(in, length, contentType); return write(in, length, contentType);
} }

View File

@ -8,7 +8,7 @@ import org.dromara.hutool.core.net.url.UrlBuilder;
import org.dromara.hutool.core.util.CharsetUtil; import org.dromara.hutool.core.util.CharsetUtil;
import org.dromara.hutool.http.client.Request; import org.dromara.hutool.http.client.Request;
import org.dromara.hutool.http.client.Response; import org.dromara.hutool.http.client.Response;
import org.dromara.hutool.http.meta.Header; import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.meta.Method; import org.dromara.hutool.http.meta.Method;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
@ -99,9 +99,9 @@ public class HttpRequestTest {
@Disabled @Disabled
public void getDeflateTest() { public void getDeflateTest() {
final Response res = Request.of("https://comment.bilibili.com/67573272.xml") final Response res = Request.of("https://comment.bilibili.com/67573272.xml")
.header(Header.ACCEPT_ENCODING, "deflate") .header(HeaderName.ACCEPT_ENCODING, "deflate")
.send(); .send();
Console.log(res.header(Header.CONTENT_ENCODING)); Console.log(res.header(HeaderName.CONTENT_ENCODING));
Console.log(res.body()); Console.log(res.body());
} }
@ -156,11 +156,11 @@ public class HttpRequestTest {
// 方式1全局设置 // 方式1全局设置
HttpGlobalConfig.setMaxRedirectCount(1); HttpGlobalConfig.setMaxRedirectCount(1);
Response execute = Request.of(url).send(); Response execute = Request.of(url).send();
Console.log(execute.getStatus(), execute.header(Header.LOCATION)); Console.log(execute.getStatus(), execute.header(HeaderName.LOCATION));
// 方式2单独设置 // 方式2单独设置
execute = Request.of(url).setMaxRedirectCount(1).send(); execute = Request.of(url).setMaxRedirectCount(1).send();
Console.log(execute.getStatus(), execute.header(Header.LOCATION)); Console.log(execute.getStatus(), execute.header(HeaderName.LOCATION));
} }
@Test @Test

View File

@ -5,7 +5,7 @@ import org.dromara.hutool.core.lang.Console;
import org.dromara.hutool.core.regex.ReUtil; import org.dromara.hutool.core.regex.ReUtil;
import org.dromara.hutool.core.util.CharsetUtil; import org.dromara.hutool.core.util.CharsetUtil;
import org.dromara.hutool.http.client.Request; import org.dromara.hutool.http.client.Request;
import org.dromara.hutool.http.meta.Header; import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.meta.Method; import org.dromara.hutool.http.meta.Method;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
@ -39,7 +39,7 @@ public class HttpUtilTest {
// 某些接口对Accept头有特殊要求此处自定义头 // 某些接口对Accept头有特殊要求此处自定义头
final String result = HttpUtil.send(Request final String result = HttpUtil.send(Request
.of("http://cmp.ishanghome.com/cmp/v1/community/queryClusterCommunity") .of("http://cmp.ishanghome.com/cmp/v1/community/queryClusterCommunity")
.header(Header.ACCEPT, "*/*")) .header(HeaderName.ACCEPT, "*/*"))
.bodyStr(); .bodyStr();
Console.log(result); Console.log(result);
} }
@ -58,7 +58,7 @@ public class HttpUtilTest {
// 自定义的默认header无效 // 自定义的默认header无效
final String result = Request final String result = Request
.of("https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=101457313&redirect_uri=http%3A%2F%2Fwww.benmovip.com%2Fpay-cloud%2Fqqlogin%2FgetCode&state=ok") .of("https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=101457313&redirect_uri=http%3A%2F%2Fwww.benmovip.com%2Fpay-cloud%2Fqqlogin%2FgetCode&state=ok")
.header(Header.USER_AGENT, null).send().bodyStr(); .header(HeaderName.USER_AGENT, null).send().bodyStr();
Console.log(result); Console.log(result);
} }

View File

@ -3,7 +3,7 @@ package org.dromara.hutool.http;
import org.dromara.hutool.core.lang.Console; import org.dromara.hutool.core.lang.Console;
import org.dromara.hutool.http.client.Request; import org.dromara.hutool.http.client.Request;
import org.dromara.hutool.http.client.Response; import org.dromara.hutool.http.client.Response;
import org.dromara.hutool.http.meta.Header; import org.dromara.hutool.http.meta.HeaderName;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -15,7 +15,7 @@ public class IssueI5TPSYTest {
final String url = "https://bsxt.gdzwfw.gov.cn/UnifiedReporting/auth/newIndex"; final String url = "https://bsxt.gdzwfw.gov.cn/UnifiedReporting/auth/newIndex";
final Response res = HttpUtil.send(Request.of(url) final Response res = HttpUtil.send(Request.of(url)
.setMaxRedirectCount(2) .setMaxRedirectCount(2)
.header(Header.USER_AGENT, "PostmanRuntime/7.29.2") .header(HeaderName.USER_AGENT, "PostmanRuntime/7.29.2")
.cookie("jsessionid=s%3ANq6YTcIHQWrHkEqOSxiQNijDMhoFNV4_.h2MVD1CkW7sOZ60OSnPs7m4K%2FhENfYy%2FdzjKvSiZF4E")); .cookie("jsessionid=s%3ANq6YTcIHQWrHkEqOSxiQNijDMhoFNV4_.h2MVD1CkW7sOZ60OSnPs7m4K%2FhENfYy%2FdzjKvSiZF4E"));
Console.log(res.body()); Console.log(res.body());
} }

View File

@ -3,7 +3,7 @@ package org.dromara.hutool.http;
import org.dromara.hutool.core.lang.Console; import org.dromara.hutool.core.lang.Console;
import org.dromara.hutool.http.client.Request; import org.dromara.hutool.http.client.Request;
import org.dromara.hutool.http.client.Response; import org.dromara.hutool.http.client.Response;
import org.dromara.hutool.http.meta.Header; import org.dromara.hutool.http.meta.HeaderName;
import org.brotli.dec.BrotliInputStream; import org.brotli.dec.BrotliInputStream;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -17,7 +17,7 @@ public class IssueI5XBCFTest {
@SuppressWarnings("resource") @SuppressWarnings("resource")
final Response s = Request.of("https://static-exp1.licdn.com/sc/h/br/1cp0oqz322bdprj3qd4pojqix") final Response s = Request.of("https://static-exp1.licdn.com/sc/h/br/1cp0oqz322bdprj3qd4pojqix")
.header(Header.ACCEPT_ENCODING, "br") .header(HeaderName.ACCEPT_ENCODING, "br")
.send(); .send();
Console.log(s.body()); Console.log(s.body());
} }

View File

@ -2,7 +2,7 @@ package org.dromara.hutool.http;
import org.dromara.hutool.core.lang.Console; import org.dromara.hutool.core.lang.Console;
import org.dromara.hutool.http.client.Request; import org.dromara.hutool.http.client.Request;
import org.dromara.hutool.http.meta.Header; import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.meta.Method; import org.dromara.hutool.http.meta.Method;
import org.dromara.hutool.json.JSONUtil; import org.dromara.hutool.json.JSONUtil;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
@ -24,7 +24,7 @@ public class RestTest {
.body(JSONUtil.ofObj() .body(JSONUtil.ofObj()
.set("aaa", "aaaValue") .set("aaa", "aaaValue")
.set("键2", "值2").toString()); .set("键2", "值2").toString());
Assertions.assertEquals("application/json;charset=UTF-8", request.header(Header.CONTENT_TYPE)); Assertions.assertEquals("application/json;charset=UTF-8", request.header(HeaderName.CONTENT_TYPE));
} }
@SuppressWarnings("resource") @SuppressWarnings("resource")
@ -52,7 +52,7 @@ public class RestTest {
@Disabled @Disabled
public void getWithBodyTest() { public void getWithBodyTest() {
final Request request = Request.of("http://localhost:8888/restTest")// final Request request = Request.of("http://localhost:8888/restTest")//
.header(Header.CONTENT_TYPE, "application/json") .header(HeaderName.CONTENT_TYPE, "application/json")
.body(JSONUtil.ofObj() .body(JSONUtil.ofObj()
.set("aaa", "aaaValue") .set("aaa", "aaaValue")
.set("键2", "值2").toString()); .set("键2", "值2").toString());

View File

@ -6,7 +6,7 @@ import org.dromara.hutool.core.lang.Console;
import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.http.client.Request; import org.dromara.hutool.http.client.Request;
import org.dromara.hutool.http.client.Response; import org.dromara.hutool.http.client.Response;
import org.dromara.hutool.http.meta.Header; import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.meta.Method; import org.dromara.hutool.http.meta.Method;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -69,7 +69,7 @@ public class UploadTest {
//noinspection resource //noinspection resource
final String result = Request.of(url) final String result = Request.of(url)
.method(Method.POST) .method(Method.POST)
.header(Header.USER_AGENT, "PostmanRuntime/7.28.4") .header(HeaderName.USER_AGENT, "PostmanRuntime/7.28.4")
.auth(token) .auth(token)
.form(MapUtil.of("smfile", FileUtil.file("d:/test/qrcodeCustom.png"))) .form(MapUtil.of("smfile", FileUtil.file("d:/test/qrcodeCustom.png")))
.send().bodyStr(); .send().bodyStr();

View File

@ -2,24 +2,24 @@ package org.dromara.hutool.http.server;
import org.dromara.hutool.core.lang.Console; import org.dromara.hutool.core.lang.Console;
import org.dromara.hutool.http.HttpUtil; import org.dromara.hutool.http.HttpUtil;
import org.dromara.hutool.http.meta.Header; import org.dromara.hutool.http.meta.HeaderName;
public class RedirectServerTest { public class RedirectServerTest {
public static void main(final String[] args) { public static void main(final String[] args) {
HttpUtil.createServer(8888).addAction("/redirect1", (request, response) -> { HttpUtil.createServer(8888).addAction("/redirect1", (request, response) -> {
response.addHeader(Header.LOCATION.getValue(),"http://localhost:8888/redirect2"); response.addHeader(HeaderName.LOCATION.getValue(),"http://localhost:8888/redirect2");
response.addHeader(Header.SET_COOKIE.getValue(),"redirect1=1; path=/; HttpOnly"); response.addHeader(HeaderName.SET_COOKIE.getValue(),"redirect1=1; path=/; HttpOnly");
response.send(301); response.send(301);
}).addAction("/redirect2", (request, response) -> { }).addAction("/redirect2", (request, response) -> {
response.addHeader(Header.LOCATION.getValue(),"http://localhost:8888/redirect3"); response.addHeader(HeaderName.LOCATION.getValue(),"http://localhost:8888/redirect3");
response.addHeader(Header.SET_COOKIE.getValue(), "redirect2=2; path=/; HttpOnly"); response.addHeader(HeaderName.SET_COOKIE.getValue(), "redirect2=2; path=/; HttpOnly");
response.send(301); response.send(301);
}).addAction("/redirect3", (request, response) -> { }).addAction("/redirect3", (request, response) -> {
response.addHeader(Header.LOCATION.getValue(),"http://localhost:8888/redirect4"); response.addHeader(HeaderName.LOCATION.getValue(),"http://localhost:8888/redirect4");
response.addHeader(Header.SET_COOKIE.getValue(),"redirect3=3; path=/; HttpOnly"); response.addHeader(HeaderName.SET_COOKIE.getValue(),"redirect3=3; path=/; HttpOnly");
response.send(301); response.send(301);
}).addAction("/redirect4", (request, response) -> { }).addAction("/redirect4", (request, response) -> {
final String cookie = request.getHeader(Header.COOKIE); final String cookie = request.getHeader(HeaderName.COOKIE);
Console.log(cookie); Console.log(cookie);
response.sendOk(); response.sendOk();
}).start(); }).start();

View File

@ -5,7 +5,7 @@ import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.lang.Console; import org.dromara.hutool.core.lang.Console;
import org.dromara.hutool.core.net.multipart.UploadFile; import org.dromara.hutool.core.net.multipart.UploadFile;
import org.dromara.hutool.http.meta.ContentType; import org.dromara.hutool.http.meta.ContentType;
import org.dromara.hutool.http.meta.Header; import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.HttpUtil; import org.dromara.hutool.http.HttpUtil;
import org.dromara.hutool.json.JSONUtil; import org.dromara.hutool.json.JSONUtil;
@ -59,7 +59,7 @@ public class SimpleServerTest {
res.write("0"); res.write("0");
Console.log("Write 0 OK"); Console.log("Write 0 OK");
}).addAction("/getCookie", ((request, response) -> { }).addAction("/getCookie", ((request, response) -> {
response.setHeader(Header.SET_COOKIE.toString(), response.setHeader(HeaderName.SET_COOKIE.toString(),
ListUtil.of( ListUtil.of(
new HttpCookie("cc", "123").toString(), new HttpCookie("cc", "123").toString(),
new HttpCookie("cc", "abc").toString())); new HttpCookie("cc", "abc").toString()));