修复支付网关地址空白字符
This commit is contained in:
@@ -374,7 +374,7 @@ func (c *Client) post(ctx context.Context, endpoint string, reqData map[string]a
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
url := strings.TrimRight(c.cfg.GatewayURL, "/") + endpoint
|
url := strings.TrimRight(strings.TrimSpace(c.cfg.GatewayURL), "/") + endpoint
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -125,6 +125,14 @@ func TestCreatePaymentSetsCounterParamWhenPayModeConfigured(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreatePaymentTrimsGatewayURLWhitespace(t *testing.T) {
|
||||||
|
body := captureCreatePaymentBody(t, "", "\t")
|
||||||
|
reqData := body["req_data"].(map[string]any)
|
||||||
|
if reqData["out_order_no"] != "ORDER1" {
|
||||||
|
t.Fatalf("out_order_no = %#v, want ORDER1", reqData["out_order_no"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCreatePaymentUsesShanghaiTimeWhenLocalIsUTC(t *testing.T) {
|
func TestCreatePaymentUsesShanghaiTimeWhenLocalIsUTC(t *testing.T) {
|
||||||
oldLocal := time.Local
|
oldLocal := time.Local
|
||||||
time.Local = time.UTC
|
time.Local = time.UTC
|
||||||
@@ -179,7 +187,7 @@ func testKeyPairPEM(t *testing.T, key *rsa.PrivateKey) (string, string) {
|
|||||||
return privatePEM, certPEM
|
return privatePEM, certPEM
|
||||||
}
|
}
|
||||||
|
|
||||||
func captureCreatePaymentBody(t *testing.T, payMode string) map[string]any {
|
func captureCreatePaymentBody(t *testing.T, payMode string, gatewaySuffix ...string) map[string]any {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
var captured map[string]any
|
var captured map[string]any
|
||||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -199,8 +207,12 @@ func captureCreatePaymentBody(t *testing.T, payMode string) map[string]any {
|
|||||||
t.Fatalf("generate key: %v", err)
|
t.Fatalf("generate key: %v", err)
|
||||||
}
|
}
|
||||||
privatePEM, certPEM := testKeyPairPEM(t, key)
|
privatePEM, certPEM := testKeyPairPEM(t, key)
|
||||||
|
gatewayURL := server.URL
|
||||||
|
if len(gatewaySuffix) > 0 {
|
||||||
|
gatewayURL += gatewaySuffix[0]
|
||||||
|
}
|
||||||
client := NewClient(Config{
|
client := NewClient(Config{
|
||||||
GatewayURL: server.URL,
|
GatewayURL: gatewayURL,
|
||||||
AppID: "app-1",
|
AppID: "app-1",
|
||||||
SerialNo: "serial-1",
|
SerialNo: "serial-1",
|
||||||
MerchantID: "merchant-1",
|
MerchantID: "merchant-1",
|
||||||
|
|||||||
@@ -395,7 +395,7 @@ func notifyParamKeys(params map[string]string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) validate() error {
|
func (c *Client) validate() error {
|
||||||
if c.cfg.GatewayURL == "" || c.cfg.MerchantID == "" || c.cfg.SignKey == "" {
|
if strings.TrimSpace(c.cfg.GatewayURL) == "" || c.cfg.MerchantID == "" || c.cfg.SignKey == "" {
|
||||||
return ErrConfigIncomplete
|
return ErrConfigIncomplete
|
||||||
}
|
}
|
||||||
if c.cfg.SignType != "" && !strings.EqualFold(c.cfg.SignType, "MD5") {
|
if c.cfg.SignType != "" && !strings.EqualFold(c.cfg.SignType, "MD5") {
|
||||||
@@ -409,7 +409,7 @@ func (c *Client) post(ctx context.Context, params map[string]string) (map[string
|
|||||||
for key, value := range params {
|
for key, value := range params {
|
||||||
values.Set(key, value)
|
values.Set(key, value)
|
||||||
}
|
}
|
||||||
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, c.cfg.GatewayURL, strings.NewReader(values.Encode()))
|
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, strings.TrimSpace(c.cfg.GatewayURL), strings.NewReader(values.Encode()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package paymentconfig
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"hfb_sys/backend/internal/model"
|
"hfb_sys/backend/internal/model"
|
||||||
|
|
||||||
@@ -12,6 +13,7 @@ import (
|
|||||||
|
|
||||||
// Create 创建配置
|
// Create 创建配置
|
||||||
func (r *Repository) Create(ctx context.Context, req CreateRequest, actorID uint64, meta AuditMeta) (*ConfigDTO, error) {
|
func (r *Repository) Create(ctx context.Context, req CreateRequest, actorID uint64, meta AuditMeta) (*ConfigDTO, error) {
|
||||||
|
req = normalizeCreateRequest(req)
|
||||||
// 验证必填字段
|
// 验证必填字段
|
||||||
if err := r.validateCreateRequest(req); err != nil {
|
if err := r.validateCreateRequest(req); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -91,10 +93,9 @@ func (r *Repository) Create(ctx context.Context, req CreateRequest, actorID uint
|
|||||||
return &dto, nil
|
return &dto, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update 更新配置
|
|
||||||
|
|
||||||
// Update 更新配置
|
// Update 更新配置
|
||||||
func (r *Repository) Update(ctx context.Context, id uint64, req UpdateRequest, actorID uint64, meta AuditMeta) (*ConfigDTO, error) {
|
func (r *Repository) Update(ctx context.Context, id uint64, req UpdateRequest, actorID uint64, meta AuditMeta) (*ConfigDTO, error) {
|
||||||
|
req = normalizeUpdateRequest(req)
|
||||||
if req.SignType != nil && *req.SignType != "" && !isValidSignType(*req.SignType) {
|
if req.SignType != nil && *req.SignType != "" && !isValidSignType(*req.SignType) {
|
||||||
return nil, ErrInvalidSignType
|
return nil, ErrInvalidSignType
|
||||||
}
|
}
|
||||||
@@ -222,7 +223,66 @@ func (r *Repository) Update(ctx context.Context, id uint64, req UpdateRequest, a
|
|||||||
return &dto, nil
|
return &dto, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete 删除配置
|
// normalizeCreateRequest 清理后台创建配置时常见的复制粘贴空白,避免隐藏字符进入渠道请求。
|
||||||
|
func normalizeCreateRequest(req CreateRequest) CreateRequest {
|
||||||
|
req.Name = strings.TrimSpace(req.Name)
|
||||||
|
req.Provider = strings.TrimSpace(req.Provider)
|
||||||
|
req.MerchantID = strings.TrimSpace(req.MerchantID)
|
||||||
|
req.GatewayURL = strings.TrimSpace(req.GatewayURL)
|
||||||
|
req.SignKey = strings.TrimSpace(req.SignKey)
|
||||||
|
req.NotifyKey = strings.TrimSpace(req.NotifyKey)
|
||||||
|
req.NotifyURL = strings.TrimSpace(req.NotifyURL)
|
||||||
|
req.JumpURL = strings.TrimSpace(req.JumpURL)
|
||||||
|
req.PayWay = strings.TrimSpace(req.PayWay)
|
||||||
|
req.JSPayFlag = strings.TrimSpace(req.JSPayFlag)
|
||||||
|
req.SignType = strings.TrimSpace(req.SignType)
|
||||||
|
req.Status = strings.TrimSpace(req.Status)
|
||||||
|
req.Environment = strings.TrimSpace(req.Environment)
|
||||||
|
req.ExtraConfig = trimExtraConfig(req.ExtraConfig)
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalizeUpdateRequest 清理后台更新配置时提交的字符串字段。
|
||||||
|
func normalizeUpdateRequest(req UpdateRequest) UpdateRequest {
|
||||||
|
trimStringPtr(req.Name)
|
||||||
|
trimStringPtr(req.MerchantID)
|
||||||
|
trimStringPtr(req.GatewayURL)
|
||||||
|
trimStringPtr(req.SignKey)
|
||||||
|
trimStringPtr(req.NotifyKey)
|
||||||
|
trimStringPtr(req.NotifyURL)
|
||||||
|
trimStringPtr(req.JumpURL)
|
||||||
|
trimStringPtr(req.PayWay)
|
||||||
|
trimStringPtr(req.JSPayFlag)
|
||||||
|
trimStringPtr(req.SignType)
|
||||||
|
trimStringPtr(req.Status)
|
||||||
|
trimStringPtr(req.Environment)
|
||||||
|
req.ExtraConfig = trimExtraConfig(req.ExtraConfig)
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|
||||||
|
// trimStringPtr 原地清理可选字符串字段。
|
||||||
|
func trimStringPtr(value *string) {
|
||||||
|
if value == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*value = strings.TrimSpace(*value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// trimExtraConfig 清理扩展配置里的字符串值,证书和私钥内部换行会被保留。
|
||||||
|
func trimExtraConfig(config map[string]any) map[string]any {
|
||||||
|
if config == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
trimmed := make(map[string]any, len(config))
|
||||||
|
for key, value := range config {
|
||||||
|
if text, ok := value.(string); ok {
|
||||||
|
trimmed[key] = strings.TrimSpace(text)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
trimmed[key] = value
|
||||||
|
}
|
||||||
|
return trimmed
|
||||||
|
}
|
||||||
|
|
||||||
// Delete 删除配置
|
// Delete 删除配置
|
||||||
func (r *Repository) Delete(ctx context.Context, id uint64, actorID uint64, meta AuditMeta) error {
|
func (r *Repository) Delete(ctx context.Context, id uint64, actorID uint64, meta AuditMeta) error {
|
||||||
|
|||||||
Reference in New Issue
Block a user