package fuiou import ( "encoding/xml" "fmt" "net/url" "strings" ) // VerifyNotify 验证回调通知并解析数据 // rawBody: 原始请求 body(可能包含 req= 前缀的 URL 编码 GBK XML) func (c *Client) VerifyNotify(rawBody []byte) (*NotifyRequest, error) { content := string(rawBody) // 处理 req= 前缀(富友回调可能以 form 格式发送) if strings.HasPrefix(content, "req=") { content = content[4:] } // URL 解码 decoded, err := url.QueryUnescape(content) if err != nil { return nil, fmt.Errorf("URL 解码回调数据失败: %w", err) } // GBK → UTF-8 utf8Bytes, err := GBKToUTF8([]byte(decoded)) if err != nil { return nil, fmt.Errorf("GBK 转 UTF-8 失败: %w", err) } // 替换编码声明 utf8Str := strings.Replace(string(utf8Bytes), `encoding="GBK"`, `encoding="UTF-8"`, 1) // XML 解析 var notify NotifyRequest if err := xml.Unmarshal([]byte(utf8Str), ¬ify); err != nil { return nil, fmt.Errorf("XML 解析回调数据失败: %w", err) } // 验证签名 if err := c.Verify(¬ify, notify.Sign); err != nil { return nil, fmt.Errorf("回调签名验证失败: %w", err) } // 检查结果码 if notify.ResultCode != "000000" { return ¬ify, fmt.Errorf("回调结果非成功: %s - %s", notify.ResultCode, notify.ResultMsg) } return ¬ify, nil } // BuildNotifySuccessResponse 构建成功响应(GBK 编码的 XML) func BuildNotifySuccessResponse() []byte { return buildNotifyResponse("000000", "success") } // BuildNotifyFailResponse 构建失败响应(GBK 编码的 XML) func BuildNotifyFailResponse(msg string) []byte { return buildNotifyResponse("999999", msg) } // buildNotifyResponse 构建回调响应 XML(GBK 编码) func buildNotifyResponse(code, msg string) []byte { resp := NotifyResponse{ ResultCode: code, ResultMsg: msg, } xmlBytes, err := xml.Marshal(resp) if err != nil { return []byte(`999999internal error`) } xmlStr := `` + string(xmlBytes) gbkBytes, err := utf8ToGBK([]byte(xmlStr)) if err != nil { return []byte(xmlStr) } return gbkBytes }