在调用聊天记录查询API时出现以下错误:
{"@timestamp":"2025-04-13T13:26:59.039+08:00","caller":"resultx/httpResponse.go:61","content":"【im】 err field \"conversationId\" is not set","level":"error","span":"7c20b19360c876ab","trace":"d63018a2b4072d97685e8206df695035"}
实际请求URL为:
GET /v1/im/chatlog?conversationId=0x0000003000000006_0x0000003000000002&startSendTime=&endSendTime&count=20
- 错误信息:系统报告
field "conversationId" is not set,表明必填字段conversationId未被正确设置 - 请求参数:URL中确实包含conversationId参数
- 参数格式:参数值为
0x0000003000000006_0x0000003000000002,包含特殊字符和十六进制值
// ChatLogReq结构定义 (types.go)
type ChatLogReq struct {
ConversationId string `json:"conversationId"`
StartSendTime int64 `json:"startSendTime,omitempty"`
EndSendTime int64 `json:"endSendTime,omitempty"`
Count int64 `json:"count,omitempty"`
}
// 参数解析代码 (getChatLogHandler.go)
func getChatLogHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ChatLogReq
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
// ...省略后续代码
}
}- 参数解析机制:
httpx.Parse在处理GET请求时,会尝试从URL查询参数中提取数据映射到结构体 - 标签不匹配:go-zero框架可能对查询参数名和JSON标签名的处理存在差异
- 特殊字符处理:conversationId中包含下划线等特殊字符,可能在URL参数解析过程中出现问题
func getChatLogHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ChatLogReq
// 手动获取URL参数
req.ConversationId = r.URL.Query().Get("conversationId")
// 如果conversationId为空,返回错误
if req.ConversationId == "" {
httpx.ErrorCtx(r.Context(), w, errors.New("缺少会话ID参数"))
return
}
// 提取其他可选参数
if startTime := r.URL.Query().Get("startSendTime"); startTime != "" {
startTimeInt, err := strconv.ParseInt(startTime, 10, 64)
if err == nil {
req.StartSendTime = startTimeInt
}
}
if endTime := r.URL.Query().Get("endSendTime"); endTime != "" {
endTimeInt, err := strconv.ParseInt(endTime, 10, 64)
if err == nil {
req.EndSendTime = endTimeInt
}
}
if count := r.URL.Query().Get("count"); count != "" {
countInt, err := strconv.ParseInt(count, 10, 64)
if err == nil {
req.Count = countInt
}
}
l := logic.NewGetChatLogLogic(r.Context(), svcCtx)
resp, err := l.GetChatLog(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}type ChatLogReq struct {
ConversationId string `json:"conversationId" form:"conversationId"`
StartSendTime int64 `json:"startSendTime,omitempty" form:"startSendTime,optional"`
EndSendTime int64 `json:"endSendTime,omitempty" form:"endSendTime,optional"`
Count int64 `json:"count,omitempty" form:"count,optional"`
}// API定义修改
// 从: GET /chatlog (ChatLogReq) returns (ChatLogResp)
// 到: GET /chatlog/:conversationId (ChatLogReq) returns (ChatLogResp)
// 然后修改handler
func getChatLogHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ChatLogReq
req.ConversationId = chi.URLParam(r, "conversationId") // 使用chi路由或其他库获取路径参数
// 解析其他查询参数
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
// ...其他代码不变
}
}最优方案是方案二:修改API定义文件中的类型定义,为结构体字段添加form标签。这样当代码重新生成时,生成的代码已包含正确的参数解析能力,不会因为重新生成而丢失修复。
在im.api文件中为ChatLogReq结构体添加form标签:
type (
ChatLogReq {
ConversationId string `json:"conversationId" form:"conversationId"`
StartSendTime int64 `json:"startSendTime,omitempty" form:"startSendTime,optional"`
EndSendTime int64 `json:"endSendTime,omitempty" form:"endSendTime,optional"`
Count int64 `json:"count,omitempty" form:"count,optional"`
}
)修改后运行以下命令重新生成代码:
goctl api go -api im.api -dir .这种方式的优势是:
- 修复永久生效,不会被代码重新生成覆盖
- 遵循go-zero框架的设计理念
- 不需要手动修改生成的处理函数
- 同时兼容JSON请求体和URL查询参数