You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6.7 KiB
6.7 KiB
自动解析和自动编码实现方案
核心需求
- 自动解析:服务端接收到数据后,自动解析为header和struct,Handler直接使用
- 自动编码:Handler返回数据后,自动编码并发送
实现方案
1. 路由配置指定类型
在注册路由时指定请求和响应的类型:
// 定义请求和响应类型
type LoginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
}
type LoginResponse struct {
Code int `json:"code"`
Token string `json:"token"`
}
// 注册路由时指定类型
router.RegisterString(
"login",
loginHandler,
router.WithRequestType(&LoginRequest{}),
router.WithResponseType(&LoginResponse{}), // 可选
)
2. 服务器自动解析
在服务器接收到数据后,自动进行解析:
// 服务器接收到数据
func (h *eventHandler) OnTraffic(c gnet.Conn) {
// 1. 读取原始数据
rawData, _ := c.Peek(-1)
// 2. 创建Context(包含Request和Response)
ctx := h.createContext(c, rawData)
// 3. 路由匹配(会返回路由配置,包含请求类型)
route, handler := h.router.Match(rawData, ctx)
if route == nil {
return
}
// 4. 自动解析请求数据
if route.RequestType() != nil {
h.parseRequest(ctx, rawData, route)
}
// 5. 执行Handler(Handler中可以直接使用解析后的数据)
handler(ctx)
// 6. 自动发送响应(Response.Write()会自动编码)
ctx.Response().Send()
}
3. 自动解析逻辑
func (h *eventHandler) parseRequest(ctx Context, rawData []byte, route Route) {
req := ctx.Request()
protocol := req.Protocol()
codec := h.getCodec(route)
// 1. 协议解码(提取帧头和数据)
header, bodyBytes, err := protocol.Decode(rawData)
if err != nil {
// 处理错误
return
}
req.SetHeader(header)
req.SetDataBytes(bodyBytes)
// 2. 数据解码(将字节解码为结构体)
if route.RequestType() != nil {
body := reflect.New(route.RequestType().Elem()).Interface()
if err := codec.Decode(bodyBytes, body); err != nil {
// 处理错误
return
}
req.SetData(body)
}
}
4. 自动编码逻辑
func (resp *responseImpl) Write(data interface{}) error {
codec := resp.codec
protocol := resp.protocol
// 1. 编解码器编码(Go对象 → 字节)
bodyBytes, err := codec.Encode(data)
if err != nil {
return err
}
// 2. 协议编码(添加帧头)
header := resp.Header()
frameData, err := protocol.Encode(bodyBytes, header)
if err != nil {
return err
}
// 3. 写入连接
return resp.conn.Write(frameData)
}
Handler使用示例
有帧头协议
type LoginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
}
type LoginResponse struct {
Code int `json:"code"`
Token string `json:"token"`
}
// 注册路由
router.RegisterString(
"login",
loginHandler,
router.WithRequestType(&LoginRequest{}),
)
// Handler实现(数据已自动解析)
func loginHandler(ctx Context) error {
req := ctx.Request()
resp := ctx.Response()
// 直接使用解析后的数据
loginReq := req.Data().(*LoginRequest)
username := loginReq.Username
password := loginReq.Password
// 读取协议帧头(如果有)
header := req.Header()
if header != nil {
messageType := header.Get("message_type")
// 使用帧头信息
}
// 处理业务逻辑
token := authenticate(username, password)
// 设置响应帧头(如果有)
respHeader := resp.Header()
if respHeader != nil {
respHeader.Set("message_type", 0x02)
respHeader.Set("status", 0)
}
// 写入响应(自动编码)
return resp.Write(LoginResponse{
Code: 200,
Token: token,
})
}
无帧头协议
type EchoRequest struct {
Message string `json:"message"`
}
type EchoResponse struct {
Message string `json:"message"`
}
// 注册路由
router.RegisterString(
"echo",
echoHandler,
router.WithRequestType(&EchoRequest{}),
)
// Handler实现
func echoHandler(ctx Context) error {
req := ctx.Request()
resp := ctx.Response()
// 直接使用解析后的数据(无帧头协议,header为nil)
echoReq := req.Data().(*EchoRequest)
// 写入响应(自动编码,协议会自动添加\n等分隔符)
return resp.Write(EchoResponse{
Message: echoReq.Message,
})
}
路由接口更新
// RouteOption 路由选项
type RouteOption func(*routeConfig)
// WithRequestType 指定请求类型
func WithRequestType(typ interface{}) RouteOption {
return func(cfg *routeConfig) {
cfg.requestType = reflect.TypeOf(typ)
}
}
// WithResponseType 指定响应类型(可选,主要用于验证)
func WithResponseType(typ interface{}) RouteOption {
return func(cfg *routeConfig) {
cfg.responseType = reflect.TypeOf(typ)
}
}
// Router接口更新
type Router interface {
// Register 注册路由(支持选项)
Register(matcher Matcher, handler Handler, opts ...RouteOption) Route
// RegisterString 注册字符串路由(支持选项)
RegisterString(pattern string, handler Handler, opts ...RouteOption) Route
// ... 其他方法
}
数据流程
读数据(自动解析)
1. 数据到达 → Connection.Read()
↓
2. 创建Context和Request/Response
↓
3. 路由匹配 → 找到对应的路由和请求类型
↓
4. 协议解码 → Protocol.Decode() → Header + DataBytes
↓
5. 数据解码 → Codec.Decode() → Go Struct
↓
6. 设置到Request → Request.SetData(struct)
↓
7. Handler执行 → 直接使用req.Data().(*MyStruct)
写数据(自动编码)
1. Handler调用 → resp.Write(struct)
↓
2. 编解码器编码 → Codec.Encode() → []byte
↓
3. 协议编码 → Protocol.Encode() → Header + Data
↓
4. 写入连接 → Connection.Write()
实现步骤
- ✅ 更新Request和Response接口
- ⏳ 更新路由接口,支持指定请求/响应类型
- ⏳ 实现自动解析逻辑
- ⏳ 实现自动编码逻辑
- ⏳ 更新服务器代码
- ⏳ 更新协议实现
- ⏳ 编写测试用例
优势
- 自动化:数据自动解析,无需手动调用Decode
- 类型安全:使用强类型,编译时检查
- 简洁:Handler代码简洁,直接使用结构体
- 灵活:支持有帧头和无帧头协议
- 可配置:通过路由配置指定类型