|
|
# 数据流程分析 - 当前实现状态
|
|
|
|
|
|
## 问题解答
|
|
|
|
|
|
### 1. 读数据流程
|
|
|
|
|
|
**你期望的流程:**
|
|
|
```
|
|
|
read bytes -> protocol decode (data bytes) -> codec decode (go struct 或其它结构)
|
|
|
```
|
|
|
|
|
|
**当前实际实现:**
|
|
|
```
|
|
|
read bytes -> SetRequest(raw bytes) -> 路由匹配 -> 处理器
|
|
|
```
|
|
|
|
|
|
**问题:** ❌ **当前实现中没有进行protocol decode和codec decode!**
|
|
|
|
|
|
数据是**原始字节直接传递给处理器**,没有经过任何解码。
|
|
|
|
|
|
### 2. 写数据流程
|
|
|
|
|
|
**你期望的流程:**
|
|
|
```
|
|
|
write any or bytes -> codec encode (bytes) -> protocol encode (bytes)
|
|
|
```
|
|
|
|
|
|
**当前实际实现:**
|
|
|
```go
|
|
|
WriteAny(go struct) -> codec.Encode(data) -> protocol.Encode(encodedData) (可选) -> Write(bytes)
|
|
|
```
|
|
|
|
|
|
**结论:** ✅ **写数据流程是正确的!**
|
|
|
|
|
|
流程是:
|
|
|
1. Go对象(struct/map等)
|
|
|
2. 编解码器编码(codec.Encode)→ 字节数组
|
|
|
3. 协议编码(protocol.Encode,可选)→ 包含协议帧头的字节数组
|
|
|
4. 写入连接(Write)
|
|
|
|
|
|
### 3. 完整的数据流程(当前状态)
|
|
|
|
|
|
#### 写数据流程 ✅
|
|
|
```
|
|
|
处理器中:
|
|
|
ctx.WriteAny(struct{...})
|
|
|
↓
|
|
|
codec.Encode(struct) → []byte (JSON/Binary/Protobuf等)
|
|
|
↓
|
|
|
protocol.Encode([]byte) → []byte (包含Magic、长度、校验和等,可选)
|
|
|
↓
|
|
|
conn.Write([]byte) → 客户端
|
|
|
```
|
|
|
|
|
|
#### 读数据流程 ❌ (未实现)
|
|
|
```
|
|
|
客户端 → conn.Read() → []byte (原始字节)
|
|
|
↓
|
|
|
SetRequest([]byte) → ctx.Request() (仍然是原始字节)
|
|
|
↓
|
|
|
路由匹配 → 处理器
|
|
|
↓
|
|
|
处理器中直接使用 ctx.Request() (原始字节,未解码)
|
|
|
```
|
|
|
|
|
|
**问题:** 读数据时没有进行:
|
|
|
- ❌ protocol decode(去除协议帧头)
|
|
|
- ❌ codec decode(将字节解码为Go对象)
|
|
|
|
|
|
### 4. 自定义协议帧头问题
|
|
|
|
|
|
**你的问题:**
|
|
|
> 如果我需要在 write 时写入一些自定义协议帧头数据呢?或者在write之前写入呢?该怎么办?
|
|
|
|
|
|
**当前限制:**
|
|
|
|
|
|
1. **协议编码是自动的:** 如果启用`EnableProtocolEncode`,协议编码会自动在`WriteAny`中执行,无法手动控制
|
|
|
2. **无法在协议帧头之前写入数据:** 当前没有API支持在协议编码之前或之后写入额外的自定义数据
|
|
|
3. **无法自定义协议帧头格式:** 协议帧头格式由协议实现决定(如nnet协议的Magic、长度、校验和),无法自定义
|
|
|
|
|
|
**解决方案:**
|
|
|
|
|
|
#### 方案1:直接使用 Write 方法(绕过自动编码)
|
|
|
```go
|
|
|
// 手动构建完整的协议帧
|
|
|
func handler(ctx ctxpkg.Context) error {
|
|
|
// 1. 准备数据
|
|
|
data := []byte("your data")
|
|
|
|
|
|
// 2. 手动添加自定义协议帧头
|
|
|
header := []byte("CUSTOM_HEADER")
|
|
|
frame := append(header, data...)
|
|
|
|
|
|
// 3. 直接写入(绕过codec和protocol编码)
|
|
|
return ctx.Write(frame)
|
|
|
}
|
|
|
```
|
|
|
|
|
|
#### 方案2:在协议编码后追加数据
|
|
|
```go
|
|
|
func handler(ctx ctxpkg.Context) error {
|
|
|
// 1. 使用WriteAny自动编码
|
|
|
resp := Response{Code: 200}
|
|
|
ctx.WriteAny(resp) // 自动进行codec encode和protocol encode
|
|
|
|
|
|
// 2. 追加自定义数据
|
|
|
customData := []byte("custom footer")
|
|
|
ctx.Write(customData)
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
```
|
|
|
|
|
|
#### 方案3:自定义协议实现
|
|
|
```go
|
|
|
// 实现自定义协议,在Encode方法中添加自定义帧头
|
|
|
type CustomProtocol struct {
|
|
|
// ...
|
|
|
}
|
|
|
|
|
|
func (p *CustomProtocol) Encode(data []byte) ([]byte, error) {
|
|
|
// 添加自定义协议帧头
|
|
|
header := []byte("CUSTOM_HEADER")
|
|
|
// ... 其他协议帧头字段
|
|
|
return append(header, data...), nil
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## 需要实现的功能
|
|
|
|
|
|
### 1. 读数据解码支持
|
|
|
|
|
|
需要实现:
|
|
|
- ✅ protocol decode(去除协议帧头,提取数据部分)
|
|
|
- ✅ codec decode(将字节解码为Go对象)
|
|
|
|
|
|
**建议的读数据流程:**
|
|
|
```
|
|
|
read bytes → protocol.Decode(bytes) → data bytes → codec.Decode(data bytes) → go struct
|
|
|
```
|
|
|
|
|
|
### 2. 写数据增强
|
|
|
|
|
|
需要支持:
|
|
|
- ✅ 在协议编码之前写入自定义数据
|
|
|
- ✅ 在协议编码之后写入自定义数据
|
|
|
- ✅ 自定义协议帧头格式
|
|
|
|
|
|
**建议的API:**
|
|
|
```go
|
|
|
// 在协议编码之前写入
|
|
|
ctx.WriteBeforeProtocol(data []byte) error
|
|
|
|
|
|
// 在协议编码之后写入
|
|
|
ctx.WriteAfterProtocol(data []byte) error
|
|
|
|
|
|
// 写入自定义协议帧头
|
|
|
ctx.WriteHeader(header []byte) error
|
|
|
```
|
|
|
|
|
|
## 当前实现总结
|
|
|
|
|
|
### ✅ 已实现
|
|
|
1. **写数据编码:** codec encode → protocol encode (可选)
|
|
|
2. **自动编解码器匹配:** 根据配置自动选择编解码器
|
|
|
3. **协议层编码:** 支持协议层编码(如nnet协议)
|
|
|
|
|
|
### ❌ 未实现
|
|
|
1. **读数据解码:** 没有protocol decode和codec decode
|
|
|
2. **自定义协议帧头:** 无法灵活控制协议帧头的写入
|
|
|
3. **解码后的请求数据:** 处理器无法直接获取解码后的Go对象
|
|
|
|
|
|
## 建议
|
|
|
|
|
|
1. **实现读数据解码:** 在`OnTraffic`或路由匹配之前,先进行protocol decode和codec decode
|
|
|
2. **增强Context API:** 添加`WriteHeader`、`WriteBeforeProtocol`、`WriteAfterProtocol`等方法
|
|
|
3. **支持解码后的请求数据:** 添加`DecodedRequest()`方法,返回解码后的Go对象
|
|
|
|