package requestUtil import ( "bytes" "encoding/json" "errors" "fmt" "io" "log" "net/http" "strconv" "strings" "time" _type "xianyv/type" "xianyv/utils/md5Util" ) // MakeAPIRequest 通用API请求函数 func MakeAPIRequest(appId int, appSecret, domain, path string, requestData interface{}) ([]byte, error) { // json格式化 bytesData, err := json.Marshal(requestData) if err != nil { return nil, fmt.Errorf("JSON序列化错误: %v", err) } // 发起请求时的时间戳(秒) timestamp := time.Now().Unix() // 获取签名 sign := md5Util.GenSign(appId, appSecret, timestamp, bytesData) fmt.Printf("sign: %v \n", sign) // 请求url url := fmt.Sprintf("%v%v?appid=%v×tamp=%v&sign=%v", domain, path, appId, timestamp, sign) fmt.Printf("请求url: %v \n", url) // 发起请求,使用带超时的 client 并限制可读取的响应大小,防止对端返回过大内容导致 OOM client := &http.Client{Timeout: 30 * time.Second} resp, err := client.Post(url, "application/json", bytes.NewReader(bytesData)) if err != nil { req := _type.ErrResponse{ Code: 0, Msg: fmt.Errorf("HTTP请求错误: %v", err).Error(), Data: nil, } response, _ := json.Marshal(req) return response, err } fmt.Printf("响应: %v \n", resp) defer resp.Body.Close() // 限制最大可读响应大小,例如 10MB(视实际需求调整) const maxRespBytes = 10 * 1024 * 1024 // 10MB limitedReader := io.LimitReader(resp.Body, maxRespBytes+1) body, err := io.ReadAll(limitedReader) if err != nil { req := _type.ErrResponse{ Code: 0, Msg: fmt.Errorf("读取响应错误: %v", err).Error(), Data: nil, } response, _ := json.Marshal(req) return response, err } // 如果响应超过限制,返回错误 if int64(len(body)) > 10*1024*1024 { req := _type.ErrResponse{ Code: 0, Msg: fmt.Errorf("响应大小超过限制: %d bytes", len(body)).Error(), Data: nil, } response, _ := json.Marshal(req) return response, fmt.Errorf("response too large: %d bytes", len(body)) } return body, nil } // RequestParams 解析请求参数 func RequestParams(r *http.Request) (_type.Body, error) { var body _type.Body var err error // 转换各个字段 appIdStr := r.FormValue("appId") body.AppSecret = r.FormValue("appSecret") body.OuterId = r.FormValue("token") body.Token = r.FormValue("token") apiShopIdStr := r.FormValue("apiShopId") typePlatformStr := r.FormValue("typePlatform") shopIdStr := r.FormValue("shopId") body.ShopToken = r.FormValue("shopToken") body.ShopName = r.FormValue("shopName") provinceStr := r.FormValue("province") cityStr := r.FormValue("city") districtStr := r.FormValue("district") body.TypeClass = r.FormValue("typeClass") body.TypeGoods = r.FormValue("typeGoods") body.CatIds = r.FormValue("catIds") shopStr := r.FormValue("shop[]") stuffStatusStr := r.FormValue("stuffStatus") bookDataStr := r.FormValue("bookData[]") body.ItemKey = r.FormValue("itemKey") body.OuterId = r.FormValue("outerId") // 转换数值参数 body.AppId, _ = strconv.Atoi(appIdStr) body.ApiShopId, _ = strconv.Atoi(apiShopIdStr) body.TypePlatform, _ = strconv.Atoi(typePlatformStr) body.ShopId, _ = strconv.Atoi(shopIdStr) if i, err := strconv.ParseInt(provinceStr, 10, 32); err == nil { body.Province = int32(i) } else { body.Province = 0 } if i, err := strconv.ParseInt(cityStr, 10, 32); err == nil { body.City = int32(i) } else { body.City = 0 } if i, err := strconv.ParseInt(districtStr, 10, 32); err == nil { body.District = int32(i) } else { body.District = 0 } body.StuffStatus, _ = strconv.Atoi(stuffStatusStr) // shop非空校验,修复字符编码问题 if shopStr != "" { // 清理可能的非法字符 shopStr = strings.TrimSpace(shopStr) shopStr = strings.Trim(shopStr, `"'`) // 移除BOM标记 if strings.HasPrefix(shopStr, "\uFEFF") { shopStr = strings.TrimPrefix(shopStr, "\uFEFF") } err = json.Unmarshal([]byte(shopStr), &body.Shop) if err != nil { log.Printf("JSON格式错误,Shop: %v", err) log.Printf("错误数据内容: %s", shopStr) return body, fmt.Errorf("JSON格式错误,Shop: %v", err) } } else { log.Println("Shop不应为空") return body, errors.New("Shop不应为空") } // bookData非空校验,修复字符编码问题 if bookDataStr != "" { bookDataStr = strings.TrimSpace(bookDataStr) bookDataStr = strings.Trim(bookDataStr, `"'`) if strings.HasPrefix(bookDataStr, "\uFEFF") { bookDataStr = strings.TrimPrefix(bookDataStr, "\uFEFF") } err = json.Unmarshal([]byte(bookDataStr), &body.BookData) if err != nil { log.Printf("JSON格式错误,解析bookData: %v", err) return body, fmt.Errorf("JSON格式错误,解析bookData: %v", err) } } else { log.Printf("bookData不应为空") return body, errors.New("bookData不应为空") } return body, err }