用 Router 组织服务端路由
这篇教程的目标很明确:在你已经能启动 Feat HTTP 服务的前提下,进一步学会把一个处理器扩展成一组可维护的路由规则。
你会完成什么
Section titled “你会完成什么”- 创建一个
Router - 注册静态路由、路径参数路由和按 HTTP 方法区分的路由
- 使用
Session保存简单状态 - 为指定路径添加拦截器
- 已完成 Feat Core 快速入门
- 了解 Java Lambda 表达式
- 能使用
curl或浏览器访问本机服务
步骤 1:创建第一个 Router 服务
Section titled “步骤 1:创建第一个 Router 服务”下面的例子把多个请求路径交给 Router 统一管理:
import tech.smartboot.feat.Feat;import tech.smartboot.feat.router.Router;
public class RouterDemo { public static void main(String[] args) { Router router = new Router();
router.route("/", ctx -> { ctx.Response.write("root: " + ctx.Request.getRequestURI()); });
router.route("/users/:id", ctx -> { ctx.Response.write("userId: " + ctx.pathParam("id")); });
router.route("/articles", "GET", ctx -> { ctx.Response.write("list articles"); });
router.route("/articles", "POST", ctx -> { ctx.Response.write("create article"); });
Feat.httpServer().httpHandler(router).listen(8080); }}这里有四个关键信息:
new Router()创建路由容器route("/path", handler)注册一个路径route("/path", "GET", handler)可以按 HTTP 方法注册不同处理器Feat.httpServer().httpHandler(router)让 Router 接管请求分发
步骤 2:验证路由匹配
Section titled “步骤 2:验证路由匹配”启动程序后,依次访问下面几个请求:
curl http://localhost:8080/curl http://localhost:8080/users/42curl -X GET http://localhost:8080/articlescurl -X POST http://localhost:8080/articles预期结果:
root: /userId: 42list articlescreate article到这里你已经验证了 Router 的三个最核心能力:
- 路径分发
- 路径参数提取
- 同一路径下的多 HTTP 方法分发
路由规则怎么写
Section titled “路由规则怎么写”在 Feat Router 里,最常用的是三种模式:
| 模式 | 含义 | 示例 |
|---|---|---|
/users | 精确匹配 | 只匹配 /users |
/users/:id | 路径参数 | 匹配 /users/42 |
/static/* | 通配符 | 匹配 /static/js/app.js |
步骤 3:使用 Session 保存状态
Section titled “步骤 3:使用 Session 保存状态”Router 内置了会话能力。最简单的用法是先写入 Session,再从另一个接口读取:
import tech.smartboot.feat.Feat;import tech.smartboot.feat.core.server.Session;import tech.smartboot.feat.router.Router;
public class RouterSessionDemo { public static void main(String[] args) { Router router = new Router();
router.route("/createSession", ctx -> { ctx.session().put("flag", "ready"); ctx.Response.write("session created"); });
router.route("/session/check", ctx -> { Session session = ctx.session(); ctx.Response.write("flag: " + session.get("flag")); });
Feat.httpServer().httpHandler(router).listen(8080); }}你可以按下面顺序验证:
curl -i http://localhost:8080/createSessioncurl -i http://localhost:8080/session/check在真实浏览器里验证会更直观,因为浏览器会自动带上 Cookie。命令行测试时,如果你要跨请求保留 Cookie,需要自己维护 Cookie。
步骤 4:为指定路径添加拦截器
Section titled “步骤 4:为指定路径添加拦截器”拦截器适合做鉴权、日志、前置检查这类横切逻辑。
import tech.smartboot.feat.Feat;import tech.smartboot.feat.router.Router;
public class RouterInterceptorDemo { public static void main(String[] args) { Router router = new Router();
router.addInterceptor("/admin/*", (context, completableFuture, chain) -> { String token = context.Request.getHeader("X-Token"); if (!"feat".equals(token)) { context.Response.write("forbidden"); completableFuture.complete(null); return; } chain.proceed(context, completableFuture); });
router.route("/admin/ping", ctx -> { ctx.Response.write("ok"); });
Feat.httpServer().httpHandler(router).listen(8080); }}验证:
curl http://localhost:8080/admin/pingcurl -H 'X-Token: feat' http://localhost:8080/admin/ping预期第一条返回 forbidden,第二条返回 ok。
路由明明写了,但返回 404
Section titled “路由明明写了,但返回 404”优先检查:
- 你是否真的把
router传给了httpHandler(...) - 请求路径是否与注册路径完全一致
- 路径参数是不是写成了
:id而不是别的形式
同一路径注册多个处理器,结果不符合预期
Section titled “同一路径注册多个处理器,结果不符合预期”如果你需要区分请求方法,显式写上 "GET"、"POST" 这类 method 参数,不要只注册一个通用路径。
Session 看起来没有生效
Section titled “Session 看起来没有生效”浏览器会自动维护 Cookie,但 curl 默认不会跨请求保存 Cookie。排查 Session 问题时,优先用浏览器,或者显式处理 Cookie。
- 异步处理:当路由内出现耗时逻辑时,如何避免阻塞
- ServerOptions 配置:定制端口、线程数和调试行为
- Feat Cloud 快速入门:如果你想换成注解式控制器开发