add ProxySelector

This commit is contained in:
Looly 2024-11-29 17:21:08 +08:00
parent 5b129a1a8f
commit c2ea26e40d
19 changed files with 252 additions and 156 deletions

View File

@ -105,17 +105,6 @@ public class CronUtil {
return id; return id;
} }
/**
* 加入定时任务
*
* @param schedulingPattern 定时任务执行时间的crontab表达式
* @param task 任务
* @return 定时任务ID
*/
public static String schedule(final String schedulingPattern, final Runnable task) {
return scheduler.schedule(schedulingPattern, task);
}
/** /**
* 批量加入配置文件中的定时任务 * 批量加入配置文件中的定时任务
* *

View File

@ -238,17 +238,6 @@ public class Scheduler implements Serializable {
return this; return this;
} }
/**
* 新增Task使用随机UUID
*
* @param pattern {@link CronPattern}对应的String表达式
* @param task {@link Runnable}
* @return ID
*/
public String schedule(final String pattern, final Runnable task) {
return schedule(pattern, new RunnableTask(task));
}
/** /**
* 新增Task使用随机UUID * 新增Task使用随机UUID
* *

View File

@ -26,12 +26,12 @@ public class AddAndRemoveMainTest {
CronUtil.setMatchSecond(true); CronUtil.setMatchSecond(true);
CronUtil.start(false); CronUtil.start(false);
CronUtil.getScheduler().clear(); CronUtil.getScheduler().clear();
final String id = CronUtil.schedule("*/2 * * * * *", (Runnable) () -> Console.log("task running : 2s")); final String id = CronUtil.schedule("*/2 * * * * *", () -> Console.log("task running : 2s"));
ThreadUtil.sleep(3000); ThreadUtil.sleep(3000);
CronUtil.remove(id); CronUtil.remove(id);
Console.log("Task Removed"); Console.log("Task Removed");
CronUtil.schedule("*/3 * * * * *", (Runnable) () -> Console.log("New task add running : 3s")); CronUtil.schedule("*/3 * * * * *", () -> Console.log("New task add running : 3s"));
Console.log("New Task added."); Console.log("New Task added.");
} }
} }

View File

@ -86,7 +86,8 @@ public class CronTest {
@Test @Test
@Disabled @Disabled
public void addAndRemoveTest() { public void addAndRemoveTest() {
final String id = CronUtil.schedule("*/2 * * * * *", (Runnable) () -> Console.log("task running : 2s")); final String id = CronUtil.schedule("*/2 * * * * *",
() -> Console.log("task running : 2s"));
Console.log(id); Console.log(id);
CronUtil.remove(id); CronUtil.remove(id);

View File

@ -0,0 +1,16 @@
package org.dromara.hutool.cron.demo;
import org.dromara.hutool.core.lang.Console;
import org.dromara.hutool.cron.CronUtil;
public class SimpleDemo {
public static void main(String[] args) {
// 打开秒匹配
CronUtil.setMatchSecond(true);
// 添加任务
CronUtil.schedule("*/2 * * * * *",
() -> Console.log("Hutool task running!"));
// 启动
CronUtil.start();
}
}

View File

@ -0,0 +1,5 @@
/**
* 定时任务示例
*
*/
package org.dromara.hutool.cron.demo;

View File

@ -17,7 +17,7 @@
package org.dromara.hutool.http.client; package org.dromara.hutool.http.client;
import org.dromara.hutool.http.HttpGlobalConfig; import org.dromara.hutool.http.HttpGlobalConfig;
import org.dromara.hutool.http.proxy.HttpProxy; import org.dromara.hutool.http.proxy.ProxyInfo;
import org.dromara.hutool.http.ssl.SSLInfo; import org.dromara.hutool.http.ssl.SSLInfo;
/** /**
@ -55,7 +55,7 @@ public class ClientConfig {
/** /**
* 代理 * 代理
*/ */
private HttpProxy proxy; private ProxyInfo proxy;
/** /**
* 是否遇到响应状态码3xx时自动重定向请求 * 是否遇到响应状态码3xx时自动重定向请求
*/ */
@ -189,7 +189,7 @@ public class ClientConfig {
* *
* @return 代理 * @return 代理
*/ */
public HttpProxy getProxy() { public ProxyInfo getProxy() {
return proxy; return proxy;
} }
@ -201,16 +201,16 @@ public class ClientConfig {
* @return this * @return this
*/ */
public ClientConfig setHttpProxy(final String host, final int port) { public ClientConfig setHttpProxy(final String host, final int port) {
return setProxy(new HttpProxy(host, port)); return setProxy(new ProxyInfo(host, port));
} }
/** /**
* 设置代理 * 设置代理
* *
* @param proxy 代理 {@link HttpProxy} * @param proxy 代理 {@link ProxyInfo}
* @return this * @return this
*/ */
public ClientConfig setProxy(final HttpProxy proxy) { public ClientConfig setProxy(final ProxyInfo proxy) {
this.proxy = proxy; this.proxy = proxy;
return this; return this;
} }

View File

@ -27,6 +27,7 @@ import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.*; import org.apache.http.impl.client.*;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicHeader;
import org.dromara.hutool.core.io.IoUtil; import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.Assert;
@ -42,11 +43,12 @@ import org.dromara.hutool.http.client.body.HttpBody;
import org.dromara.hutool.http.client.cookie.InMemoryCookieStore; import org.dromara.hutool.http.client.cookie.InMemoryCookieStore;
import org.dromara.hutool.http.client.engine.AbstractClientEngine; import org.dromara.hutool.http.client.engine.AbstractClientEngine;
import org.dromara.hutool.http.meta.HeaderName; import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.proxy.HttpProxy; import org.dromara.hutool.http.proxy.ProxyInfo;
import org.dromara.hutool.http.ssl.SSLInfo; import org.dromara.hutool.http.ssl.SSLInfo;
import java.io.IOException; import java.io.IOException;
import java.net.PasswordAuthentication; import java.net.PasswordAuthentication;
import java.net.ProxySelector;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -290,18 +292,20 @@ public class HttpClient4Engine extends AbstractClientEngine {
return; return;
} }
final HttpProxy proxy = config.getProxy(); final ProxyInfo proxy = config.getProxy();
if (null != proxy) { if (null != proxy) {
final HttpHost httpHost = new HttpHost(proxy.getHost(), proxy.getPort()); final ProxySelector proxySelector = proxy.getProxySelector();
clientBuilder.setProxy(httpHost); if(null != proxySelector){
clientBuilder.setRoutePlanner(new SystemDefaultRoutePlanner(proxySelector));
}
final PasswordAuthentication auth = proxy.getAuth(); final PasswordAuthentication auth = proxy.getAuth();
if (null != auth) { if (null != auth) {
// 代理验证 // 代理验证
final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider(); final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials( credentialsProvider.setCredentials(
new AuthScope(httpHost), new AuthScope(new HttpHost(proxy.getAuthHost(), proxy.getAuthPort())),
new UsernamePasswordCredentials(auth.getUserName(), String.valueOf(auth.getPassword()))); new UsernamePasswordCredentials(auth.getUserName(), String.valueOf(auth.getPassword())));
clientBuilder.setDefaultCredentialsProvider(credsProvider); clientBuilder.setDefaultCredentialsProvider(credentialsProvider);
} }
} }
} }

View File

@ -47,7 +47,7 @@ import org.dromara.hutool.http.client.body.HttpBody;
import org.dromara.hutool.http.client.cookie.InMemoryCookieStore; import org.dromara.hutool.http.client.cookie.InMemoryCookieStore;
import org.dromara.hutool.http.client.engine.AbstractClientEngine; import org.dromara.hutool.http.client.engine.AbstractClientEngine;
import org.dromara.hutool.http.meta.HeaderName; import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.proxy.HttpProxy; import org.dromara.hutool.http.proxy.ProxyInfo;
import org.dromara.hutool.http.ssl.SSLInfo; import org.dromara.hutool.http.ssl.SSLInfo;
import java.io.IOException; import java.io.IOException;
@ -296,16 +296,15 @@ public class HttpClient5Engine extends AbstractClientEngine {
return; return;
} }
final HttpProxy proxy = config.getProxy(); final ProxyInfo proxy = config.getProxy();
if (null != proxy) { if (null != proxy) {
final HttpHost httpHost = new HttpHost(proxy.getHost(), proxy.getPort()); clientBuilder.setProxySelector(proxy.getProxySelector());
clientBuilder.setProxy(httpHost);
final PasswordAuthentication auth = proxy.getAuth(); final PasswordAuthentication auth = proxy.getAuth();
if (null != auth) { if (null != auth) {
// 代理验证 // 代理验证
final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider(); final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials( credsProvider.setCredentials(
new AuthScope(httpHost), new AuthScope(new HttpHost(proxy.getAuthHost(), proxy.getAuthPort())),
new UsernamePasswordCredentials(auth.getUserName(), auth.getPassword())); new UsernamePasswordCredentials(auth.getUserName(), auth.getPassword()));
clientBuilder.setDefaultCredentialsProvider(credsProvider); clientBuilder.setDefaultCredentialsProvider(credsProvider);
} }

View File

@ -19,6 +19,7 @@ package org.dromara.hutool.http.client.engine.jdk;
import org.dromara.hutool.core.io.IORuntimeException; import org.dromara.hutool.core.io.IORuntimeException;
import org.dromara.hutool.core.io.IoUtil; import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.net.url.UrlBuilder; import org.dromara.hutool.core.net.url.UrlBuilder;
import org.dromara.hutool.core.net.url.UrlUtil;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.text.split.SplitUtil; import org.dromara.hutool.core.text.split.SplitUtil;
import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.core.util.ObjUtil;
@ -31,9 +32,12 @@ import org.dromara.hutool.http.client.engine.AbstractClientEngine;
import org.dromara.hutool.http.meta.HeaderName; 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;
import org.dromara.hutool.http.proxy.ProxyInfo;
import java.io.IOException; import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.util.List; import java.util.List;
/** /**
@ -125,8 +129,14 @@ public class JdkClientEngine extends AbstractClientEngine {
private JdkHttpConnection buildConn(final Request message) { private JdkHttpConnection buildConn(final Request message) {
final ClientConfig config = ObjUtil.defaultIfNull(this.config, ClientConfig::of); final ClientConfig config = ObjUtil.defaultIfNull(this.config, ClientConfig::of);
final URL url = message.handledUrl().toURL();
Proxy proxy = null;
final ProxyInfo proxyInfo = config.getProxy();
if(null != proxyInfo){
proxy = proxyInfo.selectFirst(UrlUtil.toURI(url));
}
final JdkHttpConnection conn = JdkHttpConnection final JdkHttpConnection conn = JdkHttpConnection
.of(message.handledUrl().toURL(), config.getProxy()) .of(url, proxy)
.setConnectTimeout(config.getConnectionTimeout()) .setConnectTimeout(config.getConnectionTimeout())
.setReadTimeout(config.getReadTimeout()) .setReadTimeout(config.getReadTimeout())
.setMethod(message.method())// .setMethod(message.method())//

View File

@ -27,13 +27,14 @@ 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.InMemoryCookieStore; import org.dromara.hutool.http.client.cookie.InMemoryCookieStore;
import org.dromara.hutool.http.client.engine.AbstractClientEngine; import org.dromara.hutool.http.client.engine.AbstractClientEngine;
import org.dromara.hutool.http.proxy.HttpProxy; import org.dromara.hutool.http.proxy.ProxyInfo;
import org.dromara.hutool.http.ssl.SSLInfo; import org.dromara.hutool.http.ssl.SSLInfo;
import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager; import javax.net.ssl.X509TrustManager;
import java.io.IOException; import java.io.IOException;
import java.net.PasswordAuthentication; import java.net.PasswordAuthentication;
import java.net.ProxySelector;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
@ -178,10 +179,13 @@ public class OkHttpEngine extends AbstractClientEngine {
* @param config 配置 * @param config 配置
*/ */
private static void setProxy(final OkHttpClient.Builder builder, final ClientConfig config) { private static void setProxy(final OkHttpClient.Builder builder, final ClientConfig config) {
final HttpProxy proxy = config.getProxy(); final ProxyInfo proxyInfo = config.getProxy();
if (null != proxy) { if (null != proxyInfo) {
builder.proxy(proxy); final ProxySelector proxySelector = proxyInfo.getProxySelector();
final PasswordAuthentication auth = proxy.getAuth(); if(null != proxySelector){
builder.proxySelector(proxySelector);
}
final PasswordAuthentication auth = proxyInfo.getAuth();
if (null != auth) { if (null != auth) {
builder.proxyAuthenticator(new BasicProxyAuthenticator(auth)); builder.proxyAuthenticator(new BasicProxyAuthenticator(auth));
} }

View File

@ -1,95 +0,0 @@
/*
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hutool.http.proxy;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;
/**
* HTTP代理提供代理地址和代理端口的持有
*
* @author looly
* @since 6.0.0
*/
public class HttpProxy extends Proxy {
private final String host;
private final int port;
private PasswordAuthentication auth;
/**
* 构造
*
* @param host 域名或IP
* @param port 端口
*/
public HttpProxy(final String host, final int port) {
super(Type.HTTP, new InetSocketAddress(host, port));
this.host = host;
this.port = port;
}
/**
* 获取域名或IP
*
* @return 域名或IP
*/
public String getHost() {
return host;
}
/**
* 获取端口
*
* @return 端口
*/
public int getPort() {
return port;
}
/**
* 设置代理验证信息
*
* @param user 用户名
* @param pass 密码
* @return this
*/
public HttpProxy setAuth(final String user, final char[] pass) {
return setAuth(new PasswordAuthentication(user, pass));
}
/**
* 设置代理验证信息
*
* @param auth {@link PasswordAuthentication}
* @return this
*/
public HttpProxy setAuth(final PasswordAuthentication auth) {
this.auth = auth;
return this;
}
/**
* 获取代理验证信息
*
* @return {@link PasswordAuthentication}
*/
public PasswordAuthentication getAuth() {
return this.auth;
}
}

View File

@ -0,0 +1,176 @@
/*
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hutool.http.proxy;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.http.HttpException;
import java.io.IOException;
import java.net.*;
import java.util.List;
/**
* 代理信息提供代理选择器和代理验证
*
* @author looly
* @since 6.0.0
*/
public class ProxyInfo {
private String authHost;
private int authPort;
private ProxySelector proxySelector;
private PasswordAuthentication auth;
/**
* 构造
*
* @param host 代理地址
* @param port 代理端口
*/
public ProxyInfo(final String host, final int port) {
this(new ProxySelector() {
@Override
public List<Proxy> select(final URI uri) {
return ListUtil.of(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port)));
}
@Override
public void connectFailed(final URI uri, final SocketAddress sa, final IOException ioe) {
throw new HttpException(ioe);
}
}, null);
this.authHost = host;
this.authPort = port;
}
/**
* 构造
*
* @param proxySelector {@link ProxySelector}
* @param auth 用户名和密码
*/
public ProxyInfo(final ProxySelector proxySelector, final PasswordAuthentication auth) {
this.proxySelector = proxySelector;
this.auth = auth;
}
/**
* 获取代理验证主机
*
* @return 代理验证主机
*/
public String getAuthHost() {
return authHost;
}
/**
* 设置代理验证主机
*
* @param authHost 代理验证主机
*/
public void setAuthHost(final String authHost) {
this.authHost = authHost;
}
/**
* 获取代理验证端口
*
* @return 代理验证端口
*/
public int getAuthPort() {
return authPort;
}
/**
* 设置代理验证端口
*
* @param authPort 代理验证端口
*/
public void setAuthPort(final int authPort) {
this.authPort = authPort;
}
/**
* 获取代理选择器
*
* @return {@link ProxySelector}
*/
public ProxySelector getProxySelector() {
return proxySelector;
}
/**
* 获取第一个代理<br>
* 如果代理选择器为空返回null
*
* @param uri {@link URI}
* @return {@link Proxy}
*/
public Proxy selectFirst(final URI uri){
if(null != proxySelector){
final List<Proxy> select = proxySelector.select(uri);
if(CollUtil.isNotEmpty(select)){
return select.get(0);
}
}
return null;
}
/**
* 设置代理选择器
*
* @param proxySelector {@link ProxySelector}
* @return this
*/
public ProxyInfo setProxySelector(final ProxySelector proxySelector) {
this.proxySelector = proxySelector;
return this;
}
/**
* 设置代理验证信息
*
* @param user 用户名
* @param pass 密码
* @return this
*/
public ProxyInfo setAuth(final String user, final char[] pass) {
return setAuth(new PasswordAuthentication(user, pass));
}
/**
* 设置代理验证信息
*
* @param auth {@link PasswordAuthentication}
* @return this
*/
public ProxyInfo setAuth(final PasswordAuthentication auth) {
this.auth = auth;
return this;
}
/**
* 获取代理验证信息
*
* @return {@link PasswordAuthentication}
*/
public PasswordAuthentication getAuth() {
return this.auth;
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.dromara.hutool.http; package org.dromara.hutool.http.client;
import org.dromara.hutool.core.codec.binary.Base64; import org.dromara.hutool.core.codec.binary.Base64;
import org.dromara.hutool.core.io.IORuntimeException; import org.dromara.hutool.core.io.IORuntimeException;
@ -22,8 +22,7 @@ import org.dromara.hutool.core.io.StreamProgress;
import org.dromara.hutool.core.io.file.FileUtil; 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.util.CharsetUtil; import org.dromara.hutool.core.util.CharsetUtil;
import org.dromara.hutool.http.client.HttpDownloader; import org.dromara.hutool.http.HttpGlobalConfig;
import org.dromara.hutool.http.client.Request;
import org.dromara.hutool.http.client.engine.ClientEngineFactory; import org.dromara.hutool.http.client.engine.ClientEngineFactory;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;

View File

@ -14,10 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package org.dromara.hutool.http; package org.dromara.hutool.http.client;
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.engine.jdk.JdkClientEngine; import org.dromara.hutool.http.client.engine.jdk.JdkClientEngine;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;

View File

@ -3,10 +3,12 @@ package org.dromara.hutool.http.client;
import org.dromara.hutool.core.lang.Console; import org.dromara.hutool.core.lang.Console;
import org.dromara.hutool.http.client.engine.ClientEngineFactory; import org.dromara.hutool.http.client.engine.ClientEngineFactory;
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.Test; import org.junit.jupiter.api.Test;
public class IssueIB1QHQTest { public class IssueIB1QHQTest {
@Test @Test
@Disabled
void requestByOkHttpTest() { void requestByOkHttpTest() {
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
String response = ClientEngineFactory.createEngine("OkHttp") String response = ClientEngineFactory.createEngine("OkHttp")

View File

@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
package org.dromara.hutool.http; package org.dromara.hutool.http.client;
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.HttpUtil;
import org.dromara.hutool.http.meta.HeaderName; 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;

View File

@ -14,10 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package org.dromara.hutool.http; package org.dromara.hutool.http.html;
import org.dromara.hutool.core.regex.ReUtil; import org.dromara.hutool.core.regex.ReUtil;
import org.dromara.hutool.http.html.HtmlUtil;
import org.dromara.hutool.http.meta.ContentTypeUtil; import org.dromara.hutool.http.meta.ContentTypeUtil;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;

View File

@ -14,10 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package org.dromara.hutool.http; package org.dromara.hutool.http.meta;
import org.dromara.hutool.core.util.CharsetUtil; import org.dromara.hutool.core.util.CharsetUtil;
import org.dromara.hutool.http.meta.ContentType;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;