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.

293 lines
6.7 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 自动解析和自动编码实现方案
## 核心需求
1. **自动解析**服务端接收到数据后自动解析为header和structHandler直接使用
2. **自动编码**Handler返回数据后自动编码并发送
## 实现方案
### 1. 路由配置指定类型
在注册路由时指定请求和响应的类型:
```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{}),
router.WithResponseType(&LoginResponse{}), // 可选
)
```
### 2. 服务器自动解析
在服务器接收到数据后,自动进行解析:
```go
// 服务器接收到数据
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. 执行HandlerHandler中可以直接使用解析后的数据
handler(ctx)
// 6. 自动发送响应Response.Write()会自动编码)
ctx.Response().Send()
}
```
### 3. 自动解析逻辑
```go
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. 自动编码逻辑
```go
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使用示例
### 有帧头协议
```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) 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,
})
}
```
### 无帧头协议
```go
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,
})
}
```
## 路由接口更新
```go
// 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()
```
## 实现步骤
1. ✅ 更新Request和Response接口
2. ⏳ 更新路由接口,支持指定请求/响应类型
3. ⏳ 实现自动解析逻辑
4. ⏳ 实现自动编码逻辑
5. ⏳ 更新服务器代码
6. ⏳ 更新协议实现
7. ⏳ 编写测试用例
## 优势
1. **自动化**数据自动解析无需手动调用Decode
2. **类型安全**:使用强类型,编译时检查
3. **简洁**Handler代码简洁直接使用结构体
4. **灵活**:支持有帧头和无帧头协议
5. **可配置**:通过路由配置指定类型