feat(supplier): 在飞鱼卡发送中引入随机用户代理

- 在飞鱼卡发送逻辑中添加了随机用户代理,使用 `fakeuseragent` 库生成用户代理字符串
- 更新了请求头,确保每次请求使用不同的用户代理,增强了请求的隐蔽性
- 移除了不必要的代码,简化了订单创建和请求处理逻辑
- 新增了日志记录,提升了调试能力和错误追踪的准确性
This commit is contained in:
danial
2025-07-21 21:40:33 +08:00
parent fed35f0872
commit 925e9a8641
4 changed files with 96 additions and 57 deletions

1
go.mod
View File

@@ -17,6 +17,7 @@ require (
github.com/go-sql-driver/mysql v1.9.3
github.com/go-stomp/stomp/v3 v3.1.3
github.com/google/uuid v1.6.0
github.com/iunary/fakeuseragent v1.0.0
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/prometheus/client_golang v1.22.0

4
go.sum
View File

@@ -51,8 +51,6 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU=
github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/go-stomp/stomp/v3 v3.1.3 h1:5/wi+bI38O1Qkf2cc7Gjlw7N5beHMWB/BxpX+4p/MGI=
@@ -70,6 +68,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5uk
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/iunary/fakeuseragent v1.0.0 h1:QlxZqFFzb9oDd6p7478/AYeljJJwI74IRfxi/vs/Egs=
github.com/iunary/fakeuseragent v1.0.0/go.mod h1:opcHYShMkPA8s621QaycSxAyFnFgfOnu2bxb07HzuUE=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=

View File

@@ -6,11 +6,11 @@ import (
"errors"
"fmt"
"gateway/internal/config"
"gateway/internal/models/road"
"gateway/internal/otelTrace"
"gateway/internal/utils"
"net/http"
"net/url"
"regexp"
"sort"
"strings"
"time"
@@ -20,7 +20,7 @@ import (
"github.com/duke-git/lancet/v2/maputil"
"github.com/duke-git/lancet/v2/pointer"
"github.com/duke-git/lancet/v2/random"
"github.com/widuu/gojson"
"github.com/iunary/fakeuseragent"
"go.uber.org/zap"
)
@@ -28,60 +28,14 @@ type SendCardTaskTypeFlyFish struct {
sendCardTaskTypeSendCardTaskBase
}
func (s *SendCardTaskTypeFlyFish) HandleSendCardTask(ctx context.Context, orderItem OrderPoolItem, task SendCardTask) error {
// 解析url
payUrl, err := url.Parse(orderItem.PayURL)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("无心返回结果", zap.Error(err))
return errors.New("提交链接解析失败")
}
req := httplib.NewBeegoRequestWithCtx(ctx, "https://liuliu-pay.com/index/square/index", "POST").
Retries(3).RetryDelay(time.Second*3).
SetTimeout(time.Second*5, time.Second*5).SetProxy(func(req *http.Request) (*url.URL, error) {
proxy, err2 := utils.DMProxyStrategyInstance.GetProxy(ctx, "")
if err2 != nil || proxy == "" {
otelTrace.Logger.WithContext(ctx).Error("获取代理失败", zap.Error(err))
return nil, err
}
return url.Parse(proxy)
})
paths := strings.Split(payUrl.Path, "/")
if len(paths) == 0 {
return errors.New("提交链接解析失败")
}
req.Header("x-requested-with", "XMLHttpRequest")
req.Param("card_num", task.CardInfo.CardNo)
req.Param("card_pass", task.CardInfo.Data)
req.Param("pay_osn", paths[len(paths)-1])
respStr, err := req.String()
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("飞鱼下单请求失败", zap.Error(err))
return err
}
respData := struct {
Code int `json:"code"`
Msg string `json:"msg"`
}{}
err = json.Unmarshal([]byte(respStr), &respData)
otelTrace.Logger.WithContext(ctx).Info("飞鱼下单返回", zap.String("resp", respStr), zap.Any("respData", respData), zap.String("pay_osn", paths[len(paths)-1]), zap.String("card_num", task.CardInfo.CardNo), zap.String("card_pass", task.CardInfo.Data))
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("飞鱼下单响应解析失败", zap.Error(err))
return err
}
if respData.Code != 200 {
return errors.New(respData.Msg)
}
return nil
}
func (s *SendCardTaskTypeFlyFish) CreateOrder(ctx context.Context, roadUid string, faceValue float64) (OrderPoolItem, error) {
roadInfo := road.GetRoadInfoByRoadUid(ctx, roadUid)
// roadInfo := road.GetRoadInfoByRoadUid(ctx, roadUid)
// 组装参数
payOsn := fmt.Sprintf("%d%d", time.Now().UnixNano(), random.RandInt(1000, 9999)) // 简单订单号生成
cardType := gojson.Json(roadInfo.Params).Get("card_type").Tostring()
merchantId := gojson.Json(roadInfo.Params).Get("merchant_id").Tostring()
paySecret := gojson.Json(roadInfo.Params).Get("paySecret").Tostring()
// cardType := gojson.Json(roadInfo.Params).Get("card_type").Tostring()
// merchantId := gojson.Json(roadInfo.Params).Get("merchant_id").Tostring()
// paySecret := gojson.Json(roadInfo.Params).Get("paySecret").Tostring()
cfg := new(config.Config)
timestamp := fmt.Sprintf("%d", time.Now().Unix())
nonce := random.RandString(16)
@@ -90,9 +44,9 @@ func (s *SendCardTaskTypeFlyFish) CreateOrder(ctx context.Context, roadUid strin
notifyUrl := fmt.Sprintf("%s%s", cfg.GatewayAddr(), "/flyfish/notify")
params := ""
// cardType := "45"
// merchantId := "202514117509"
// paySecret := "684cf0f8476ffSHbM1rWD7py80PVK3mek"
cardType := "45"
merchantId := "202514117509"
paySecret := "684cf0f8476ffSHbM1rWD7py80PVK3mek"
// 组装签名参数map
paramMap := map[string]any{
@@ -156,6 +110,88 @@ func (s *SendCardTaskTypeFlyFish) CreateOrder(ctx context.Context, roadUid strin
}, nil
}
func (s *SendCardTaskTypeFlyFish) HandleSendCardTask(ctx context.Context, orderItem OrderPoolItem, task SendCardTask) error {
// 解析url
payUrl, err := url.Parse(orderItem.PayURL)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("无心返回结果", zap.Error(err))
return errors.New("提交链接解析失败")
}
paths := strings.Split(payUrl.Path, "/")
if len(paths) == 0 {
return errors.New("提交链接解析失败")
}
randomAgent := fakeuseragent.RandomUserAgent()
req := httplib.NewBeegoRequestWithCtx(ctx, fmt.Sprintf("http://www.xksale.com/index/card/%s", paths[len(paths)-1]), "GET").SetTimeout(time.Second*3, time.Second*3).RetryDelay(time.Second * 3).Retries(3).SetProxy(func(req *http.Request) (*url.URL, error) {
proxy, err2 := utils.DMProxyStrategyInstance.GetProxy(ctx, "")
if err2 != nil || proxy == "" {
otelTrace.Logger.WithContext(ctx).Error("获取代理失败", zap.Error(err))
return nil, err
}
return url.Parse(proxy)
})
req.Header("User-Agent", randomAgent)
respStr, err := req.String()
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("飞鱼下单请求失败", zap.Error(err))
return err
}
re := regexp.MustCompile(`let orderId = '(\d+)'`)
matches := re.FindStringSubmatch(respStr)
if len(matches) < 2 {
return errors.New("订单号解析失败")
}
orderId := matches[1]
otelTrace.Logger.WithContext(ctx).Info("飞鱼下单返回", zap.String("resp", respStr), zap.String("orderId", orderId))
req = httplib.NewBeegoRequestWithCtx(ctx, "http://www.xksale.com/index/taobao", "POST").SetTimeout(time.Second*3, time.Second*3).RetryDelay(time.Second * 3).Retries(3).SetProxy(func(req *http.Request) (*url.URL, error) {
proxy, err2 := utils.DMProxyStrategyInstance.GetProxy(ctx, "")
if err2 != nil || proxy == "" {
otelTrace.Logger.WithContext(ctx).Error("获取代理失败", zap.Error(err))
return nil, err
}
return url.Parse(proxy)
})
req.Header("User-Agent", randomAgent)
req.Param("orderId", orderId)
_, _ = req.String()
req = httplib.NewBeegoRequestWithCtx(ctx, "https://liuliu-pay.com/index/square/index", "POST").
Retries(3).RetryDelay(time.Second*3).
SetTimeout(time.Second*5, time.Second*5).SetProxy(func(req *http.Request) (*url.URL, error) {
proxy, err2 := utils.DMProxyStrategyInstance.GetProxy(ctx, "")
if err2 != nil || proxy == "" {
otelTrace.Logger.WithContext(ctx).Error("获取代理失败", zap.Error(err))
return nil, err
}
return url.Parse(proxy)
})
req.Header("x-requested-with", "XMLHttpRequest")
req.Param("card_num", task.CardInfo.CardNo)
req.Param("card_pass", task.CardInfo.Data)
req.Param("pay_osn", paths[len(paths)-1])
req.Header("User-Agent", randomAgent)
respStr, err = req.String()
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("飞鱼下单请求失败", zap.Error(err))
return err
}
respData := struct {
Code int `json:"code"`
Msg string `json:"msg"`
}{}
err = json.Unmarshal([]byte(respStr), &respData)
otelTrace.Logger.WithContext(ctx).Info("飞鱼下单返回", zap.String("resp", respStr), zap.Any("respData", respData), zap.String("pay_osn", paths[len(paths)-1]), zap.String("card_num", task.CardInfo.CardNo), zap.String("card_pass", task.CardInfo.Data))
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("飞鱼下单响应解析失败", zap.Error(err))
return err
}
if respData.Code != 200 {
return errors.New(respData.Msg)
}
return nil
}
func (s *SendCardTaskTypeFlyFish) QueryOrder(ctx context.Context, orderItem OrderPoolItem, task SendCardTask) error {
return nil
}

View File

@@ -0,0 +1,2 @@
2025-07-21 21:39:23 INFO card_sender/flyfish.go:214 飞鱼签名 {"sign": "app_secret=684cf0f8476ffSHbM1rWD7py80PVK3mek&card_price=100&card_type=45&merchant_id=202514117509&nonce=DyhgQxmusEfYkEWR&notify_url=http://127.0.0.1:12309/flyfish/notify&pay_osn=17531051631071064003495&timestamp=1753105163"}
2025-07-21 21:39:23 INFO card_sender/flyfish.go:93 飞鱼下单返回 {"resp": "{\"code\":200,\"show\":1,\"msg\":\"下单成功\",\"data\":{\"url\":\"http:\\/\\/www.xksale.com\\/index\\/pay\\/88CB795DCF41B9E39FD7A27A23DC718730DF64CC4E221B21\",\"pay_osn\":\"88CB795DCF41B9E39FD7A27A23DC718730DF64CC4E221B21\",\"params\":\"\"}}", "respData": {"code":200,"msg":"下单成功","data":{"url":"http://www.xksale.com/index/pay/88CB795DCF41B9E39FD7A27A23DC718730DF64CC4E221B21","pay_osn":"88CB795DCF41B9E39FD7A27A23DC718730DF64CC4E221B21","params":""}}}