wastnet 是一款零依赖、自研的 Java Web 服务器,核心基于 JDK 原生 NIO 构建 Reactor 多路复用模型,不依赖 Netty、Tomcat 等任何第三方网络库。其 HTTP/2(h2 / h2c)协议栈从 HPACK、Huffman 到 ALPN 均为完全自研实现,是框架的核心特色之一;在基准测试中吞吐对标 Undertow。 本文介绍 wastnet 的路由分发组件 HttpRouterHandler。它是一个高性能、支持链式配置的 HTTP 路由 Handler,能力覆盖 精确匹配、前缀匹配、正则匹配、HTTP 方法过滤、反向代理、静态资源、SSE、WebSocket / h2c 升级,并内置上下文路径(context path)自动前缀与路由级拦截器链。 本文从 API 形态到匹配优先级、再到实战示例,完整介绍它的使用方式。 为什么需要 HttpRouterHandler HTTPServer 的 requestHandler 接受一个 HttpRequestHandler,但原生 Handler 只有一个 handle(request, response) 入口,所有路径判断要自己写。当接口变多,你需要一个「按路径分发」的组件: HTTPServer.of(8080) .requestHandler(router) .start(); HttpRouterHandler 自身也实现 HttpRequestHandler,可直接挂到 HTTPServer 上,内部再把请求派发给各个子路由。 创建与上下文路径 // 根上下文("/"),所有路由直接挂在根下 HttpRouterHandler router = new HttpRouterHandler(); // 带上下文路径,例如部署在 /api 下 HttpRouterHandler router = new HttpRouterHandler("/api"); 上下文路径规则: 必须以 / 开头,否则自动补 /; 尾部多余的 / 会被自动裁剪(/api/ → /api); 所有通过 route / exactRoute / get / post / ws / h2c 注册的子路由,匹配时都会自动叠加该上下文路径; 访问根 / 且配置非空 contextPath 时,默认 301 重定向到 contextPath/(可用 autoRedirect(false) 关闭)。 匹配类型 HttpRouterHandler 提供三种匹配语义,按注册方式区分: 1. 精确匹配 exactRoute 路径完全一致才命中,无正则开销,性能最好。 router.exactRoute("/user", (path, req, resp) -> resp.status(200).body("User".getBytes())); 还可限制 HTTP 方法: router.exactRoute("/user", route, HttpMethod.GET, HttpMethod.POST); 2. 前缀匹配 route 默认把路径当作前缀:/api 匹配 /api、/api/xxx、/api/yyy/zzz。 router.route("/api", apiHandler); 3. 正则匹配 以 ^ 开头即视为正则;以 $ 结尾表示严格全匹配,否则自动追加 .* 作为前缀匹配。 // 严格全匹配 /v1/resource、/v2/resource,不匹配 /v1/resource/abc router.route("^/v\\d+/resource$", regexHandler); // 正则前缀:匹配 /articles/2026 及之后任意内容 router.route("^/articles/.*", articleHandler); 4. HTTP 方法快捷注册 除 exactRoute 的方法重载外,还提供语义化快捷方法,自动约束方法并精确匹配: router.get("/user", getHandler); router.post("/user", postHandler); router.put("/user", putHandler); router.delete("/user", deleteHandler); router.patch("/user", patchHandler); 匹配优先级 一次请求进入 handle() 后的判定顺序: 上下文路径校验:不匹配 contextPath 直接 404(或根路径重定向); 路由级拦截器:返回 false 可短路请求; 精确匹配 exactRoutes(最高优先级,含 get/post/... 注册项); 健康检查路由 /health(可被精确路由覆盖); 前缀 / 正则匹配 routes(按注册顺序,第一个命中即返回); 兜底 404(默认 404 Not Found,或自定义 notFoundHandler)。 注意:exactRoute / get / post 等注册的路由属于精确匹配,优先级高于 route 前缀匹配。因此同路径优先走精确项。 反向代理 把一个前缀下的请求转发到后端服务,支持 URL 重写与协议升级: // 简单代理(不重写路径) router.proxy("/rest", "http://192.168.1.226:19028"); // 带路径重写 router.proxy("/rest", "http://192.168.1.226:19028", true); // 完整配置:升级、读超时、自定义 rewrite 函数 HttpProxyConfig config = HttpProxyConfig.target("http://192.168.1.226:19028") .upgrade(true) .readTimeout(5000) .rewrite(path -> path.replaceFirst("^/rest", "")); router.proxy("/rest", config); 静态资源 HttpResourceRoute 负责静态文件服务(ETag、Last-Modified、GZIP 等由框架处理): router.resource(new HttpResourceRoute("/", "./dist")); routePath 为资源挂载路径,框架会自动叠加 contextPath 作为 base path。 SSE 服务端推送 一行注册 Server-Sent Events 端点,框架管理异步生命周期: router.sse("/events", emitter -> { executor.submit(() -> { emitter.emit("hello"); emitter.close(); }); }); // 自定义超时(毫秒) router.sse("/events", 60_000, emitter -> { /* ... */ }); WebSocket 升级 继承 DefaultUpgradeHandler,注册时自动叠加 contextPath: router.ws("/ws", webSocketResource); 路由级拦截器 在上下文解析之后、路由分发之前运行,可形成有序链;任一返回 false 即短路请求(例如鉴权、跨域、日志): router.interceptor((path, request, response) -> { String token = request.getHeader("Authorization"); if (token == null) { response.status(401).body("unauthorized".getBytes()); return false; } return true; }); 全局开关:interceptorsDisabled(true) 可关闭所有路由级拦截器。 404 兜底 router.notFoundHandler((request, response) -> { response.status(404).body("Custom 404".getBytes()); }); 另外,针对 OPTIONS * 的 RFC 7230 星号请求,框架默认直接返回 200(查询服务器能力),不进入 404。 完整示例 参考 wastnet-test 中的 RouterHandlerTest: HttpRoute userHandler = (path, req, resp) -> resp.status(200).body(("User path: " + path).getBytes()); HttpRoute apiHandler = (path, req, resp) -> resp.status(200).body("OK".getBytes()); HttpRoute regexHandler = (path, req, resp) -> resp.status(200).body(("Regex path: " + path).getBytes()); HttpRouterHandler router = new HttpRouterHandler("/api"); router.exactRoute("/user", userHandler); router.route("/api", apiHandler); // 实际匹配 /api + 子路径 router.route("^/v\\d+/resource$", regexHandler); // 正则严格匹配 router.resource(new HttpResourceRoute("/", "./dist")); router.notFoundHandler((req, resp) -> resp.status(404).body("Custom 404".getBytes())); HTTPServer.of(8080).requestHandler(router).start(); 启动后可用以下 URL 验证: 精确匹配:/api/user 前缀匹配:/api/api/xxx 正则匹配:/api/v1/resource 静态资源:/api/index.html 小结 HttpRouterHandler 把路由、代理、静态资源、SSE、WebSocket 收敛到一个链式 API 中,零依赖、易组合。核心要点: 三种匹配:精确 > 前缀/正则,按注册顺序命中即返回; contextPath 统一管理前缀,子路由无需关心部署路径; 拦截器链支持鉴权 / 日志等横切逻辑; 代理、SSE、静态资源开箱即用。 相关链接 Gitee:https://gitee.com/xiaoch0209/wastnet GitHub:https://github.com/wycst02/wastnet 协议:Apache License 2.0 wastnet 基于 Apache 2.0 协议完全开源、免费使用,欢迎体验与反馈。
Java Web 服务器 wastnet 路由开发实战
来源:开源中国
2026年08月27日 22:01
0 阅读
分享到: