Files
toutoukan/oneKUsers/mian.go
JACKYMYPERSON 2ab7614ea0 修改秒杀
2025-09-14 21:12:37 +08:00

123 lines
4.2 KiB
Go
Raw Blame History

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