首页 > 开源 > Java Web 服务器 wastnet 路由开发实战

Java Web 服务器 wastnet 路由开发实战

OSChina资讯 2026-08-27 20:20 1 阅读 查看原文

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

HTTPServerrequestHandler 接受一个 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() 后的判定顺序:

  1. 上下文路径校验:不匹配 contextPath 直接 404(或根路径重定向);

  2. 路由级拦截器:返回 false 可短路请求;

  3. 精确匹配 exactRoutes(最高优先级,含 get/post/... 注册项);

  4. 健康检查路由 /health(可被精确路由覆盖);

  5. 前缀 / 正则匹配 routes(按注册顺序,第一个命中即返回);

  6. 兜底 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、静态资源开箱即用。

相关链接

wastnet 基于 Apache 2.0 协议完全开源、免费使用,欢迎体验与反馈。