# 自动解析和自动编码实现计划 ## 用户需求 1. **自动解析**:服务端在给定协议下自动解析数据到header和struct,Handler中直接使用 2. **自动编码**:服务端写数据时自动编码 ## 设计目标 ### Handler使用方式 ```go // 定义请求和响应类型 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.Context) error { req := ctx.Request() resp := ctx.Response() // 直接使用解析后的数据(无需手动解码) loginReq := req.Data().(*LoginRequest) // 读取协议帧头(如果有) header := req.Header() if header != nil { messageType := header.Get("message_type") } // 处理业务逻辑 token := authenticate(loginReq.Username, loginReq.Password) // 设置响应帧头(如果有) resp.Header().Set("message_type", 0x02) // 写入响应(自动编码) return resp.Write(LoginResponse{ Code: 200, Token: token, }) } ``` ## 实现步骤 ### 第一步:更新Context接口 ✅ - [x] 移除数据读写方法(Write、WriteAny等) - [x] 添加Request和Response对象 - [x] Context只负责状态管理 ### 第二步:实现Request和Response - [ ] 实现Request接口 - [ ] 存储原始数据、协议帧头、解析后的Data - [ ] 实现Data()方法返回解析后的结构体 - [ ] 实现Header()方法返回协议帧头 - [ ] 实现Response接口 - [ ] 实现Write()方法自动编码 - [ ] 实现WriteWithCodec()方法指定编解码器 - [ ] 实现Header()方法设置协议帧头 ### 第三步:更新路由接口 - [ ] 添加RouteOption支持 - [ ] WithRequestType() - 指定请求类型 - [ ] WithResponseType() - 指定响应类型(可选) - [ ] WithCodec() - 指定编解码器(可选) - [ ] 更新Route接口 - [ ] RequestType() - 获取请求类型 - [ ] ResponseType() - 获取响应类型 - [ ] Codec() - 获取编解码器 ### 第四步:实现自动解析逻辑 - [ ] 在服务器接收到数据后 - [ ] 识别协议(根据配置或数据特征) - [ ] 协议解码(Protocol.Decode()) - [ ] 识别编解码器(根据配置或数据特征) - [ ] 数据解码(Codec.Decode()) - [ ] 创建Request对象并设置解析后的数据 ### 第五步:实现自动编码逻辑 - [ ] 在Response.Write()方法中 - [ ] 编解码器编码(Codec.Encode()) - [ ] 协议编码(Protocol.Encode()) - [ ] 写入连接(Connection.Write()) ### 第六步:更新协议实现 - [ ] 更新nnet协议实现 - [ ] 实现HasHeader()方法 - [ ] 更新Encode()方法支持FrameHeader参数 - [ ] 更新Decode()方法返回FrameHeader - [ ] 更新TCP/UDP/WebSocket协议实现 - [ ] 实现无帧头协议支持 - [ ] 实现HasHeader()方法返回false ### 第七步:更新服务器代码 - [ ] 更新TCP服务器 - [ ] 实现自动解析逻辑 - [ ] 创建Request和Response对象 - [ ] 更新Context创建逻辑 - [ ] 更新UDP服务器 - [ ] 更新WebSocket服务器 - [ ] 更新Unix服务器 ### 第八步:测试和文档 - [ ] 编写测试用例 - [ ] 更新文档 - [ ] 编写使用示例 ## 关键技术点 ### 1. 类型识别和反射 ```go // 从路由配置获取请求类型 requestType := route.RequestType() if requestType != nil { // 创建结构体实例 body := reflect.New(requestType.Elem()).Interface() // 解码数据 codec.Decode(bodyBytes, body) } ``` ### 2. 协议识别 ```go // 根据配置或数据特征识别协议 func identifyProtocol(data []byte, config *Config) Protocol { // 方式1:根据配置 if config.Protocol != "" { return protocolManager.Get(config.Protocol, config.ProtocolVersion) } // 方式2:根据数据特征(如Magic字段) if len(data) >= 4 && string(data[0:4]) == "NNET" { return protocolManager.Get("nnet", "1.0") } // 方式3:默认协议 return protocolManager.GetDefault() } ``` ### 3. 编解码器识别 ```go // 根据配置或数据特征识别编解码器 func identifyCodec(data []byte, config *Config) Codec { // 方式1:根据配置 if config.Codec != nil && config.Codec.DefaultCodec != "" { return codecRegistry.Get(config.Codec.DefaultCodec) } // 方式2:根据数据特征(如JSON格式) if isJSON(data) { return codecRegistry.Get("json") } // 方式3:默认编解码器 return codecRegistry.Default() } ``` ## 数据流程 ### 读数据(自动解析) ``` 1. 数据到达 → Connection.Read() ↓ 2. 识别协议 → Protocol.Identify() ↓ 3. 协议解码 → Protocol.Decode() → Header + DataBytes ↓ 4. 识别编解码器 → Codec.Identify() ↓ 5. 获取请求类型 → Route.RequestType() ↓ 6. 数据解码 → Codec.Decode() → Go Struct ↓ 7. 创建Request对象 → Request.SetData(struct) ↓ 8. Handler执行 → req.Data().(*MyStruct) ``` ### 写数据(自动编码) ``` 1. Handler调用 → resp.Write(struct) ↓ 2. 获取编解码器 → Codec (从配置或路由) ↓ 3. 编解码器编码 → Codec.Encode() → []byte ↓ 4. 获取协议 → Protocol (从配置) ↓ 5. 协议编码 → Protocol.Encode() → Header + Data ↓ 6. 写入连接 → Connection.Write() ``` ## 优势 1. **自动化**:数据自动解析,Handler直接使用结构体 2. **类型安全**:使用强类型,编译时检查 3. **简洁**:Handler代码简洁,无需手动解码 4. **灵活**:支持有帧头和无帧头协议 5. **可配置**:通过路由配置指定类型 ## 注意事项 1. **性能**:反射操作需要优化,可以考虑使用类型缓存 2. **错误处理**:解析失败时的错误处理 3. **向后兼容**:逐步迁移,不破坏现有代码 4. **灵活性**:支持不指定类型的路由(使用原始字节)