diff --git a/CHANGELOG.md b/CHANGELOG.md index 78f6d9d03..0fd0102d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,12 +14,12 @@ * 【setting】 新增setByGroup和putByGroup,set和put标记为过期(issue#I2C42H@Gitee) * 【crypto 】 修改SymmetricAlgorithm注释(issue#1360@Github) * 【all 】 pom中将META-INF/maven下全部exclude(pr#1355@Github) -* 【core 】 pom中将META-INF/maven下全部exclude(pr#1355@Github) +* 【http 】 SimpleServer中增加addFilter等方法,并使用全局线程池 ### Bug修复 -* 【core 】 修复CsvReader读取双引号未转义问题(issur#I2BMP1@Gitee) -* 【json 】 JSONUtil.parse修复config无效问题(issur#1363@Github) -* 【http 】 修复SimpleServer返回响应内容Content-Lenth不正确的问题(issur#1358@Github) +* 【core 】 修复CsvReader读取双引号未转义问题(issue#I2BMP1@Gitee) +* 【json 】 JSONUtil.parse修复config无效问题(issue#1363@Github) +* 【http 】 修复SimpleServer返回响应内容Content-Length不正确的问题(issue#1358@Github) ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-http/src/main/java/cn/hutool/http/server/HttpServerBase.java b/hutool-http/src/main/java/cn/hutool/http/server/HttpServerBase.java index ff146ff89..d0b425e39 100644 --- a/hutool-http/src/main/java/cn/hutool/http/server/HttpServerBase.java +++ b/hutool-http/src/main/java/cn/hutool/http/server/HttpServerBase.java @@ -1,6 +1,7 @@ package cn.hutool.http.server; import cn.hutool.core.util.CharsetUtil; +import com.sun.net.httpserver.HttpContext; import com.sun.net.httpserver.HttpExchange; import java.nio.charset.Charset; @@ -34,4 +35,14 @@ public class HttpServerBase { public HttpExchange getHttpExchange() { return this.httpExchange; } + + /** + * 获取{@link HttpContext} + * + * @return {@link HttpContext} + * @since 5.5.7 + */ + public HttpContext getHttpContext() { + return getHttpExchange().getHttpContext(); + } } diff --git a/hutool-http/src/main/java/cn/hutool/http/server/SimpleServer.java b/hutool-http/src/main/java/cn/hutool/http/server/SimpleServer.java index 8af896aad..bf2fe3157 100644 --- a/hutool-http/src/main/java/cn/hutool/http/server/SimpleServer.java +++ b/hutool-http/src/main/java/cn/hutool/http/server/SimpleServer.java @@ -6,13 +6,22 @@ import cn.hutool.core.thread.GlobalThreadPool; import cn.hutool.core.util.StrUtil; import cn.hutool.http.server.action.Action; import cn.hutool.http.server.action.RootAction; +import cn.hutool.http.server.filter.HttpFilter; +import cn.hutool.http.server.filter.SimpleFilter; import cn.hutool.http.server.handler.ActionHandler; +import com.sun.net.httpserver.Filter; +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsServer; import java.io.File; import java.io.IOException; import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.Executor; /** @@ -23,7 +32,8 @@ import java.util.concurrent.Executor; */ public class SimpleServer { - HttpServer server; + private final HttpServer server; + private final List filters; /** * 构造 @@ -50,26 +60,105 @@ public class SimpleServer { * @param address 监听地址 */ public SimpleServer(InetSocketAddress address) { + this(address, null); + } + + /** + * 构造 + * + * @param address 监听地址 + * @param configurator https配置信息,用于使用自定义SSL(TLS)证书等 + */ + public SimpleServer(InetSocketAddress address, HttpsConfigurator configurator) { try { - this.server = HttpServer.create(address, 0); + if(null != configurator){ + final HttpsServer server = HttpsServer.create(address, 0); + server.setHttpsConfigurator(configurator); + this.server = server; + } else{ + this.server = HttpServer.create(address, 0); + } } catch (IOException e) { throw new IORuntimeException(e); } setExecutor(GlobalThreadPool.getExecutor()); + filters = new ArrayList<>(); + } + + /** + * 增加请求过滤器,此过滤器对所有请求有效
+ * 此方法需在以下方法前之前调用: + * + * + * + * @param filter {@link Filter} 请求过滤器 + * @return this + * @since 5.5.7 + */ + public SimpleServer addFilter(Filter filter) { + this.filters.add(filter); + return this; + } + + /** + * 增加请求过滤器,此过滤器对所有请求有效
+ * 此方法需在以下方法前之前调用: + * + * + * + * @param filter {@link Filter} 请求过滤器 + * @return this + * @since 5.5.7 + */ + public SimpleServer addFilter(HttpFilter filter) { + return addFilter(new SimpleFilter() { + @Override + public void doFilter(HttpExchange httpExchange, Chain chain) throws IOException { + filter.doFilter(new HttpServerRequest(httpExchange), new HttpServerResponse(httpExchange), chain); + } + }); } /** * 增加请求处理规则 * - * @param path 路径 - * @param handler 处理器 + * @param path 路径,例如:/a/b 或者 a/b + * @param handler 处理器,包括请求和响应处理 * @return this + * @see #createContext(String, HttpHandler) */ public SimpleServer addHandler(String path, HttpHandler handler) { + createContext(path, handler); + return this; + } + + /** + * 创建请求映射上下文,创建后,用户访问指定路径可使用{@link HttpHandler} 中的规则进行处理 + * + * @param path 路径,例如:/a/b 或者 a/b + * @param handler 处理器,包括请求和响应处理 + * @return {@link HttpContext} + * @since 5.5.7 + */ + public HttpContext createContext(String path, HttpHandler handler) { // 非/开头的路径会报错 path = StrUtil.addPrefixIfNot(path, StrUtil.SLASH); - this.server.createContext(path, handler); - return this; + final HttpContext context = this.server.createContext(path, handler); + // 增加整体过滤器 + context.getFilters().addAll(this.filters); + return context; } /** diff --git a/hutool-http/src/main/java/cn/hutool/http/server/filter/HttpFilter.java b/hutool-http/src/main/java/cn/hutool/http/server/filter/HttpFilter.java new file mode 100644 index 000000000..1b65d7af2 --- /dev/null +++ b/hutool-http/src/main/java/cn/hutool/http/server/filter/HttpFilter.java @@ -0,0 +1,26 @@ +package cn.hutool.http.server.filter; + +import cn.hutool.http.server.HttpServerRequest; +import cn.hutool.http.server.HttpServerResponse; +import com.sun.net.httpserver.Filter; + +import java.io.IOException; + +/** + * 过滤器接口,用于简化{@link Filter} 使用 + * + * @author looly + * @since 5.5.7 + */ +@FunctionalInterface +public interface HttpFilter { + + /** + * 执行过滤 + * @param req {@link HttpServerRequest} 请求对象,用于获取请求内容 + * @param res {@link HttpServerResponse} 响应对象,用于写出内容 + * @param chain {@link Filter.Chain} + * @throws IOException IO异常 + */ + void doFilter(HttpServerRequest req, HttpServerResponse res, Filter.Chain chain) throws IOException; +} diff --git a/hutool-http/src/main/java/cn/hutool/http/server/filter/SimpleFilter.java b/hutool-http/src/main/java/cn/hutool/http/server/filter/SimpleFilter.java new file mode 100644 index 000000000..c0f6f787d --- /dev/null +++ b/hutool-http/src/main/java/cn/hutool/http/server/filter/SimpleFilter.java @@ -0,0 +1,17 @@ +package cn.hutool.http.server.filter; + +import com.sun.net.httpserver.Filter; + +/** + * 匿名简单过滤器,跳过了描述 + * + * @author looly + * @since 5.5.7 + */ +public abstract class SimpleFilter extends Filter { + + @Override + public String description() { + return "Anonymous Filter"; + } +} diff --git a/hutool-http/src/main/java/cn/hutool/http/server/filter/package-info.java b/hutool-http/src/main/java/cn/hutool/http/server/filter/package-info.java new file mode 100644 index 000000000..feae032a7 --- /dev/null +++ b/hutool-http/src/main/java/cn/hutool/http/server/filter/package-info.java @@ -0,0 +1,4 @@ +/** + * {@link com.sun.net.httpserver.Filter} 实现包装 + */ +package cn.hutool.http.server.filter; \ No newline at end of file diff --git a/hutool-http/src/test/java/cn/hutool/http/server/SimpleServerTest.java b/hutool-http/src/test/java/cn/hutool/http/server/SimpleServerTest.java index a16c96a1a..842ecccd0 100644 --- a/hutool-http/src/test/java/cn/hutool/http/server/SimpleServerTest.java +++ b/hutool-http/src/test/java/cn/hutool/http/server/SimpleServerTest.java @@ -11,6 +11,10 @@ public class SimpleServerTest { public static void main(String[] args) { HttpUtil.createServer(8888) + .addFilter(((req, res, chain) -> { + Console.log("Filter: " + req.getPath()); + chain.doFilter(req.getHttpExchange()); + })) // 设置默认根目录,classpath/html .setRoot(FileUtil.file("html")) // get数据测试,返回请求的PATH @@ -46,7 +50,10 @@ public class SimpleServerTest { } ) // 测试输出响应内容是否能正常返回Content-Length头信息 - .addAction("test/zeroStr", (req, res)-> res.write("0")) + .addAction("test/zeroStr", (req, res)-> { + res.write("0"); + Console.log("Write 0 OK"); + }) .start(); } }