路由与终结点
路由中间件是 Web 框架中用于将 HTTP 请求分发到对应处理逻辑(终结点)的核心组件。它负责解析请求路径、方法等信息,并根据预定义的路由规则,将请求映射到对应的处理函数或控制器。
路由中间件典型时序图
说明
Client 代表前端或第三方应用发起的 HTTP 请求。
Server 首先接收到请求,并将其传递给路由中间件。
路由中间件 负责根据请求的路径和方法查找是否有匹配的终结点(处理函数)。
如果匹配到终结点,则将请求分发给对应的终结点处理器,处理后返回响应。
如果未匹配到终结点,则直接返回 404 Not Found。
该机制实现了请求的自动分发和处理,是 Web 框架的核心能力之一。
完整流程示例
下面以一个典型的 Spire Web 项目为例,展示路由中间件的完整流程:
cangjie
import spire_web_http.*
import spire_web_hosting.*
import spire_web_routing.*
import spire_extensions_injection.*
main() {
// 1. 创建主机构造器
let builder = WebHost.createBuilder()
// 2. 注册路由服务
builder.services.addRouting()
// 3. 构建主机
let host = builder.build()
// 4. 注册路由终结点
host.useEndpoints { endpoints: EndpointRouteBuilder =>
// GET 静态路由示例
endpoints.mapGet("hello") { context =>
context.response.write("Hello Spire!")
}
// Get 动态路由路由示例
endpoints.mapGet("api/{id}") { context =>
context.response.write("id=" + context.request.routeValues["id"].toString())
}
}
// 5. 启动主机
host.run()
return 0
}
流程说明
- 注册路由服务:
builder.services.addRouting()
向依赖注入容器注册路由相关服务,为后续路由匹配做准备。 - 注册路由中间件:
host.useRouting()
(由useEndpoints
自动注册)将路由中间件加入请求管道。该中间件会在每次请求时解析 URL 路径、HTTP 方法,并查找匹配的终结点。 - 注册终结点:
host.useEndpoints { ... }
用于注册具体的路由规则和处理逻辑。每个终结点(如mapGet("hello")
)定义了请求路径和对应的处理函数。 - 请求分发:当有 HTTP 请求到达时,路由中间件会遍历所有注册的终结点,查找与请求路径和方法匹配的处理函数,并将请求交由其处理。
- 响应输出:处理函数通过
context.response.write(...)
输出响应内容,最终返回给客户端。
注册顺序
路由中间件通常应在中间件之后,授权中间件之前注册,因为它依赖于请求的身份信息进行资源访问控制。例如:
cangjie
host.useAuthentication()
host.useRouting() // 路由中间件
host.useAuthorization()
host.useEndpoints { ... }
常用扩展
动态路由(参数化路径)
cangjie
host.useEndpoints { endpoints: EndpointRouteBuilder =>
// 支持参数化路径 /api/{id}
endpoints.mapGet("api/{id}") { context =>
context.response.write("id=" + context.request.routeValues["id"].toString())
}
}
控制器路由
cangjie
// 用户控制器,路由前缀 /user
@Route["user"]
public class UserController <: Controller {
// GET /user/{name}
@HttpGet["{name}"]
public func getUser(@FromRoute name: String): String {
context.response.write("User: " + name)
return "User: " + name
}
}
main() {
let builder = WebHost.createBuilder()
builder.services.addControllers()
.addApplicationPart("default", TypeInfo.of<UserController>())
let host = builder.build()
host.useEndpoints { endpoints =>
endpoints.mapControllers()
}
host.run()
}
中间件组合
cangjie
main() {
let builder = WebHost.createBuilder()
builder.services.addRouting()
let host = builder.build()
// 异常处理中间件(lambda表达式)
host.use((context, next) => {
// 这里可以加异常处理逻辑
context.response.write("error")
next()
})
// 日志中间件(lambda表达式)
host.use((context, next) => {
// 这里可以加日志逻辑
context.response.write("log")
next()
})
// 路由中间件
host.useRouting()
host.useEndpoints { endpoints =>
endpoints.mapGet("test") { context =>
context.response.write("middleware test")
}
}
host.run()
}
最佳实践
- 路由设计应遵循 RESTful 原则,路径简洁、语义清晰。
- 参数化路由建议命名规范,避免歧义,业务逻辑中要做好参数校验。
- 路由注册顺序很重要,建议先注册认证、授权等安全相关中间件,再注册路由。
- 控制器路由适用于复杂业务,便于分层管理和单元测试。
- 动态路由和静态路由应合理区分,避免路径冲突。
- 对于高频访问的路由,可结合缓存、限流等中间件提升性能和安全性。
- 路由表建议集中管理,便于维护和扩展。
- 生产环境建议关闭未使用的调试或测试路由,减少攻击面。