发货链接返回完整域名:DELIVERY_BASE_URL 未配置时按请求 scheme+Host 推导
- GetOrCreateDeliveryLink/RestoreDeliveryLink 增加 requestBaseURL 参数 - buildDeliveryURL 优先级:DELIVERY_BASE_URL → 请求域名 → 路径 - 支持 X-Forwarded-Proto 与 TLS 判断 https
This commit is contained in:
@@ -0,0 +1,18 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// requestBaseURL 根据当前请求推导站点基础地址(如 https://skin.khhao.com)。
|
||||||
|
// 优先取配置的 DELIVERY_BASE_URL(服务层),为空时由请求的 scheme + Host 推导,
|
||||||
|
// 保证发货链接始终返回完整可访问的 URL。
|
||||||
|
func requestBaseURL(c *gin.Context) string {
|
||||||
|
scheme := "http"
|
||||||
|
if c.Request.TLS != nil || strings.EqualFold(c.GetHeader("X-Forwarded-Proto"), "https") {
|
||||||
|
scheme = "https"
|
||||||
|
}
|
||||||
|
return scheme + "://" + c.Request.Host
|
||||||
|
}
|
||||||
@@ -168,7 +168,7 @@ func (h *MerchantHandler) CreateTestOrder(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *MerchantHandler) GetDeliveryLink(c *gin.Context) {
|
func (h *MerchantHandler) GetDeliveryLink(c *gin.Context) {
|
||||||
link, err := h.deliverySvc.GetOrCreateDeliveryLink(middleware.GetMerchantID(c), c.Param("order_no"))
|
link, err := h.deliverySvc.GetOrCreateDeliveryLink(middleware.GetMerchantID(c), c.Param("order_no"), requestBaseURL(c))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeDeliveryError(c, err)
|
writeDeliveryError(c, err)
|
||||||
return
|
return
|
||||||
@@ -185,7 +185,7 @@ func (h *MerchantHandler) RevokeDeliveryLink(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *MerchantHandler) RestoreDeliveryLink(c *gin.Context) {
|
func (h *MerchantHandler) RestoreDeliveryLink(c *gin.Context) {
|
||||||
link, err := h.deliverySvc.RestoreDeliveryLink(middleware.GetMerchantID(c), c.Param("order_no"))
|
link, err := h.deliverySvc.RestoreDeliveryLink(middleware.GetMerchantID(c), c.Param("order_no"), requestBaseURL(c))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeDeliveryError(c, err)
|
writeDeliveryError(c, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ func (h *OpenV1Handler) GetDeliveryLink(c *gin.Context) {
|
|||||||
openlog.SetAction(c, openlog.ActionQuery)
|
openlog.SetAction(c, openlog.ActionQuery)
|
||||||
orderNo := c.Param("order_no")
|
orderNo := c.Param("order_no")
|
||||||
openlog.Info(c, "delivery_link start order_no=%s", orderNo)
|
openlog.Info(c, "delivery_link start order_no=%s", orderNo)
|
||||||
link, err := h.deliverySvc.GetOrCreateDeliveryLink(middleware.GetMerchantID(c), orderNo)
|
link, err := h.deliverySvc.GetOrCreateDeliveryLink(middleware.GetMerchantID(c), orderNo, requestBaseURL(c))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
openlog.Warn(c, "delivery_link fail order_no=%s err=%v", orderNo, err)
|
openlog.Warn(c, "delivery_link fail order_no=%s err=%v", orderNo, err)
|
||||||
if sc, ok := err.(interface{ HTTPStatus() int }); ok {
|
if sc, ok := err.(interface{ HTTPStatus() int }); ok {
|
||||||
|
|||||||
@@ -665,7 +665,7 @@ func optionalUint(value uint) *uint {
|
|||||||
return &out
|
return &out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DeliveryService) GetOrCreateDeliveryLink(merchantID uint, orderNo string) (*DeliveryLinkResult, error) {
|
func (s *DeliveryService) GetOrCreateDeliveryLink(merchantID uint, orderNo, requestBaseURL string) (*DeliveryLinkResult, error) {
|
||||||
orderNo = strings.TrimSpace(orderNo)
|
orderNo = strings.TrimSpace(orderNo)
|
||||||
if orderNo == "" {
|
if orderNo == "" {
|
||||||
return nil, errors.New("订单号不能为空")
|
return nil, errors.New("订单号不能为空")
|
||||||
@@ -679,7 +679,7 @@ func (s *DeliveryService) GetOrCreateDeliveryLink(merchantID uint, orderNo strin
|
|||||||
return nil, newDeliveryHTTPError(http.StatusForbidden, "发货链接已作废")
|
return nil, newDeliveryHTTPError(http.StatusForbidden, "发货链接已作废")
|
||||||
}
|
}
|
||||||
if order.DeliveryLinkExpiresAt != nil && order.DeliveryLinkExpiresAt.After(now) {
|
if order.DeliveryLinkExpiresAt != nil && order.DeliveryLinkExpiresAt.After(now) {
|
||||||
return s.buildDeliveryLinkResult(order.OrderNo, order.DeliveryLinkExpiresAt.UTC().Truncate(time.Second)), nil
|
return s.buildDeliveryLinkResult(order.OrderNo, order.DeliveryLinkExpiresAt.UTC().Truncate(time.Second), requestBaseURL), nil
|
||||||
}
|
}
|
||||||
canShip, reason := CanFulfill(order)
|
canShip, reason := CanFulfill(order)
|
||||||
if !canShip {
|
if !canShip {
|
||||||
@@ -697,7 +697,7 @@ func (s *DeliveryService) GetOrCreateDeliveryLink(merchantID uint, orderNo strin
|
|||||||
}).Error; err != nil {
|
}).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return s.buildDeliveryLinkResult(order.OrderNo, expiresAt), nil
|
return s.buildDeliveryLinkResult(order.OrderNo, expiresAt, requestBaseURL), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DeliveryService) RevokeDeliveryLink(merchantID uint, orderNo string) error {
|
func (s *DeliveryService) RevokeDeliveryLink(merchantID uint, orderNo string) error {
|
||||||
@@ -717,7 +717,7 @@ func (s *DeliveryService) RevokeDeliveryLink(merchantID uint, orderNo string) er
|
|||||||
}).Error
|
}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DeliveryService) RestoreDeliveryLink(merchantID uint, orderNo string) (*DeliveryLinkResult, error) {
|
func (s *DeliveryService) RestoreDeliveryLink(merchantID uint, orderNo, requestBaseURL string) (*DeliveryLinkResult, error) {
|
||||||
orderNo = strings.TrimSpace(orderNo)
|
orderNo = strings.TrimSpace(orderNo)
|
||||||
if orderNo == "" {
|
if orderNo == "" {
|
||||||
return nil, errors.New("订单号不能为空")
|
return nil, errors.New("订单号不能为空")
|
||||||
@@ -745,7 +745,7 @@ func (s *DeliveryService) RestoreDeliveryLink(merchantID uint, orderNo string) (
|
|||||||
}).Error; err != nil {
|
}).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return s.buildDeliveryLinkResult(order.OrderNo, expiresAt), nil
|
return s.buildDeliveryLinkResult(order.OrderNo, expiresAt, requestBaseURL), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DeliveryService) prepareOrder(orderNo string, requireCanShip bool, auth *DeliveryLinkAuth) (*DeliveryOrderInfo, *model.FulfillmentOrder, string, error) {
|
func (s *DeliveryService) prepareOrder(orderNo string, requireCanShip bool, auth *DeliveryLinkAuth) (*DeliveryOrderInfo, *model.FulfillmentOrder, string, error) {
|
||||||
@@ -842,25 +842,29 @@ func (s *DeliveryService) authorizeDeliveryLink(order *model.FulfillmentOrder, a
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DeliveryService) buildDeliveryLinkResult(orderNo string, expiresAt time.Time) *DeliveryLinkResult {
|
func (s *DeliveryService) buildDeliveryLinkResult(orderNo string, expiresAt time.Time, requestBaseURL string) *DeliveryLinkResult {
|
||||||
expiresAt = expiresAt.UTC()
|
expiresAt = expiresAt.UTC()
|
||||||
exp := expiresAt.Unix()
|
exp := expiresAt.Unix()
|
||||||
sign := s.signDeliveryLink(orderNo, exp)
|
sign := s.signDeliveryLink(orderNo, exp)
|
||||||
return &DeliveryLinkResult{
|
return &DeliveryLinkResult{
|
||||||
OrderNo: orderNo,
|
OrderNo: orderNo,
|
||||||
DeliveryURL: s.buildDeliveryURL(orderNo, exp, sign),
|
DeliveryURL: s.buildDeliveryURL(orderNo, exp, sign, requestBaseURL),
|
||||||
ExpiresAt: expiresAt,
|
ExpiresAt: expiresAt,
|
||||||
Exp: exp,
|
Exp: exp,
|
||||||
Sign: sign,
|
Sign: sign,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DeliveryService) buildDeliveryURL(orderNo string, exp int64, sign string) string {
|
func (s *DeliveryService) buildDeliveryURL(orderNo string, exp int64, sign, requestBaseURL string) string {
|
||||||
path := fmt.Sprintf("/delivery/%s/%s?exp=%d&sign=%s", url.PathEscape(s.channel), url.PathEscape(orderNo), exp, url.QueryEscape(sign))
|
path := fmt.Sprintf("/delivery/%s/%s?exp=%d&sign=%s", url.PathEscape(s.channel), url.PathEscape(orderNo), exp, url.QueryEscape(sign))
|
||||||
if s.linkBaseURL == "" {
|
base := strings.TrimRight(s.linkBaseURL, "/")
|
||||||
|
if base == "" {
|
||||||
|
base = strings.TrimRight(requestBaseURL, "/")
|
||||||
|
}
|
||||||
|
if base == "" {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
return s.linkBaseURL + path
|
return base + path
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DeliveryService) signDeliveryLink(orderNo string, exp int64) string {
|
func (s *DeliveryService) signDeliveryLink(orderNo string, exp int64) string {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func TestDeliveryLinkGenerateAuthorizeAndRevoke(t *testing.T) {
|
|||||||
t.Fatalf("create order: %v", err)
|
t.Fatalf("create order: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
link, err := deliverySvc.GetOrCreateDeliveryLink(merchantID, created.Order.OrderNo)
|
link, err := deliverySvc.GetOrCreateDeliveryLink(merchantID, created.Order.OrderNo, "https://shop.example")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("get delivery link: %v", err)
|
t.Fatalf("get delivery link: %v", err)
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ func TestDeliveryLinkGenerateAuthorizeAndRevoke(t *testing.T) {
|
|||||||
t.Fatalf("delivery_link_revoked_at should be stored")
|
t.Fatalf("delivery_link_revoked_at should be stored")
|
||||||
}
|
}
|
||||||
|
|
||||||
restored, err := deliverySvc.RestoreDeliveryLink(merchantID, created.Order.OrderNo)
|
restored, err := deliverySvc.RestoreDeliveryLink(merchantID, created.Order.OrderNo, "https://shop.example")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("restore delivery link: %v", err)
|
t.Fatalf("restore delivery link: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user