2025-09-13 20:00:34 +08:00
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"bytes"
|
|
|
|
|
|
"encoding/json"
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"net/http"
|
|
|
|
|
|
"sync"
|
2025-09-13 22:57:09 +08:00
|
|
|
|
"time"
|
2025-09-14 17:01:36 +08:00
|
|
|
|
"toutoukan/model/usermodel/userOrder"
|
2025-09-13 20:00:34 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2025-09-14 17:01:36 +08:00
|
|
|
|
// 请求体结构(Order字段对应目标商品标识)
|
2025-09-13 20:00:34 +08:00
|
|
|
|
|
|
|
|
|
|
// 响应体结构(根据实际接口响应调整)
|
|
|
|
|
|
type Response struct {
|
|
|
|
|
|
Success bool `json:"success"`
|
|
|
|
|
|
Message string `json:"message"`
|
2025-09-14 17:01:36 +08:00
|
|
|
|
// 可根据实际接口返回补充字段,如订单号、库存状态等
|
2025-09-13 20:00:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func main() {
|
2025-09-14 17:01:36 +08:00
|
|
|
|
const totalBatches = 5 // 固定发送5批请求
|
|
|
|
|
|
const batchSize = 150 // 每批固定150个请求
|
|
|
|
|
|
const interval = 5 * time.Second // 每批请求的时间间隔(可按需调整)
|
2025-09-13 22:57:09 +08:00
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
|
|
2025-09-14 17:01:36 +08:00
|
|
|
|
userID := 1 // 用户ID计数器,从1开始递增(确保每个请求用户ID唯一)
|
2025-09-13 22:57:09 +08:00
|
|
|
|
|
2025-09-14 17:01:36 +08:00
|
|
|
|
// 循环发送5批请求,每批对应不同的商品order(stock10000 ~ stock10004)
|
|
|
|
|
|
for batch := 1; batch <= totalBatches; batch++ {
|
|
|
|
|
|
// 计算当前批次的目标商品order:第1批→stock10000,第2批→stock10001...第5批→stock10004
|
|
|
|
|
|
targetOrder := fmt.Sprintf("stock1000%d", batch-1)
|
|
|
|
|
|
fmt.Printf("=== 开始第 %d 批请求 ===\n", batch)
|
|
|
|
|
|
fmt.Printf("当前批次目标商品: %s | 请求数量: %d 个 | 开始时间: %v\n",
|
|
|
|
|
|
targetOrder, batchSize, time.Now().Format("15:04:05"))
|
|
|
|
|
|
|
|
|
|
|
|
// 并发发送当前批次的150个请求
|
|
|
|
|
|
for i := 0; i < batchSize; i++ {
|
2025-09-13 22:57:09 +08:00
|
|
|
|
wg.Add(1)
|
2025-09-14 17:01:36 +08:00
|
|
|
|
// 捕获当前循环的uid和order(避免goroutine闭包引用循环变量问题)
|
|
|
|
|
|
currentUID := userID
|
|
|
|
|
|
currentOrder := targetOrder
|
|
|
|
|
|
go func(uid int, order string) {
|
2025-09-13 22:57:09 +08:00
|
|
|
|
defer wg.Done()
|
2025-09-14 17:01:36 +08:00
|
|
|
|
// 发送单个POST请求
|
|
|
|
|
|
result, err := sendPostRequest(uid, order)
|
2025-09-13 22:57:09 +08:00
|
|
|
|
if err != nil {
|
2025-09-14 17:01:36 +08:00
|
|
|
|
// 请求失败:输出错误日志(包含用户ID和商品标识)
|
|
|
|
|
|
fmt.Printf("❌ 用户 %d (商品%s) 请求失败: %v\n", uid, order, err)
|
2025-09-13 22:57:09 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-09-14 17:01:36 +08:00
|
|
|
|
// 请求成功:输出响应结果(可按需调整日志粒度,避免刷屏)
|
|
|
|
|
|
fmt.Printf("✅ 用户 %d (商品%s) 响应: 成功=%v, 消息=%s\n",
|
|
|
|
|
|
uid, order, result.Success, result.Message)
|
|
|
|
|
|
}(currentUID, currentOrder)
|
|
|
|
|
|
userID++ // 每生成一个请求,用户ID递增1
|
2025-09-13 22:57:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-14 17:01:36 +08:00
|
|
|
|
// 等待当前批次所有请求完成(确保批次内请求全部处理后,再进入下一批)
|
|
|
|
|
|
wg.Wait()
|
|
|
|
|
|
fmt.Printf("=== 第 %d 批请求全部完成 | 完成时间: %v ===\n\n",
|
|
|
|
|
|
batch, time.Now().Format("15:04:05"))
|
|
|
|
|
|
|
|
|
|
|
|
// 非最后一批请求,等待指定间隔后再发送下一批(避免请求集中压测)
|
2025-09-13 22:57:09 +08:00
|
|
|
|
if batch < totalBatches {
|
2025-09-14 17:01:36 +08:00
|
|
|
|
fmt.Printf("等待 %v 后发送下一批请求...\n\n", interval)
|
2025-09-13 22:57:09 +08:00
|
|
|
|
time.Sleep(interval)
|
|
|
|
|
|
}
|
2025-09-13 20:00:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-14 17:01:36 +08:00
|
|
|
|
fmt.Println("🎉 所有5批请求已全部完成!")
|
2025-09-13 20:00:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-14 17:01:36 +08:00
|
|
|
|
type UserRequest1 struct {
|
|
|
|
|
|
UserID int `json:"user_id"`
|
|
|
|
|
|
Order string `json:"userorder"` // 对应商品标识:stock10000 ~ stock10004
|
|
|
|
|
|
}
|
2025-09-13 20:00:34 +08:00
|
|
|
|
|
2025-09-14 17:01:36 +08:00
|
|
|
|
// 发送POST请求(接收用户ID和商品order,构造请求体)
|
|
|
|
|
|
func sendPostRequest(userID int, order string) (*Response, error) {
|
|
|
|
|
|
// 目标接口地址(根据实际部署调整)
|
|
|
|
|
|
targetURL := "http://localhost:9096/user/kill"
|
|
|
|
|
|
// 1. 构造请求体(绑定当前用户ID和目标商品order)
|
|
|
|
|
|
requestBody := userOrder.UserRequest{
|
2025-09-13 20:00:34 +08:00
|
|
|
|
UserID: userID,
|
2025-09-14 17:01:36 +08:00
|
|
|
|
Order: order,
|
2025-09-13 20:00:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-14 17:01:36 +08:00
|
|
|
|
// 2. 将请求体序列化为JSON格式
|
2025-09-13 20:00:34 +08:00
|
|
|
|
jsonBody, err := json.Marshal(requestBody)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("JSON序列化失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-14 17:01:36 +08:00
|
|
|
|
// 3. 发送POST请求(设置Content-Type为application/json)
|
|
|
|
|
|
resp, err := http.Post(
|
|
|
|
|
|
targetURL,
|
|
|
|
|
|
"application/json",
|
|
|
|
|
|
bytes.NewBuffer(jsonBody),
|
|
|
|
|
|
)
|
2025-09-13 20:00:34 +08:00
|
|
|
|
if err != nil {
|
2025-09-14 17:01:36 +08:00
|
|
|
|
return nil, fmt.Errorf("请求发送失败(网络/连接问题): %v", err)
|
2025-09-13 20:00:34 +08:00
|
|
|
|
}
|
2025-09-14 17:01:36 +08:00
|
|
|
|
defer resp.Body.Close() // 确保响应体关闭,避免资源泄漏
|
2025-09-13 20:00:34 +08:00
|
|
|
|
|
2025-09-14 17:01:36 +08:00
|
|
|
|
// 4. 解析接口响应(无论状态码是否为200,均尝试解析,便于排查问题)
|
2025-09-13 20:00:34 +08:00
|
|
|
|
var response Response
|
|
|
|
|
|
decoder := json.NewDecoder(resp.Body)
|
|
|
|
|
|
if err := decoder.Decode(&response); err != nil {
|
2025-09-14 17:01:36 +08:00
|
|
|
|
return nil, fmt.Errorf("响应解析失败(格式不匹配): %v", err)
|
2025-09-13 20:00:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-14 17:01:36 +08:00
|
|
|
|
// 5. 检查HTTP状态码(非200视为异常,返回详细信息)
|
2025-09-13 22:57:09 +08:00
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
2025-09-14 17:01:36 +08:00
|
|
|
|
// 将响应内容转为格式化JSON,便于查看完整错误信息
|
|
|
|
|
|
responseDetail, _ := json.MarshalIndent(response, "", " ")
|
2025-09-13 22:57:09 +08:00
|
|
|
|
return &response, fmt.Errorf(
|
2025-09-14 17:01:36 +08:00
|
|
|
|
"HTTP状态码异常: %d | 接口响应详情: %s",
|
2025-09-13 22:57:09 +08:00
|
|
|
|
resp.StatusCode,
|
2025-09-14 17:01:36 +08:00
|
|
|
|
responseDetail,
|
2025-09-13 22:57:09 +08:00
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-14 17:01:36 +08:00
|
|
|
|
// 6. 请求成功,返回解析后的响应
|
2025-09-13 20:00:34 +08:00
|
|
|
|
return &response, nil
|
|
|
|
|
|
}
|