refactor(sitecode): 统一各模块分销站点编码解析为公共包
- 新增 internal/sitecode 包:FromRequest 头优先解析、FromQueryThenHeader 探测接口专用、ExtractHost/IsLocalHost 提取 Host 域名 - 替换 auth/order/listing/chat/notification/withdrawal/wallet/distribution 八模块 17 处各自内联的解析逻辑,统一优先级与 TrimSpace 行为 - 修复 notification 漏 TrimSpace、探测接口会话头压过显式 query、 GetPublicSiteInfo 把 localhost Host 当站点域名查库等不一致 - 顺手清理 auth 中无引用的 extractHost 死代码 - gofmt 修复 withdrawal/presenter、chat/file/payment 测试四个历史遗留格式问题
This commit is contained in:
@@ -2,10 +2,10 @@ package auth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"hfb_sys/backend/internal/sitecode"
|
||||
"hfb_sys/backend/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -86,20 +86,18 @@ func (h *Handler) SendSMS(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
siteCode := strings.TrimSpace(firstNonEmpty(
|
||||
c.GetHeader("X-Distribution-Site-Code"),
|
||||
c.Query("distribution_site_code"),
|
||||
c.Query("site_code"),
|
||||
req.SiteCode,
|
||||
))
|
||||
siteCode := sitecode.FromRequest(c)
|
||||
if siteCode == "" {
|
||||
siteCode = strings.TrimSpace(req.SiteCode)
|
||||
}
|
||||
domain := strings.TrimSpace(firstNonEmpty(
|
||||
c.GetHeader("X-Distribution-Domain"),
|
||||
c.Query("distribution_domain"),
|
||||
c.Query("domain"),
|
||||
))
|
||||
if siteCode == "" && domain == "" {
|
||||
host := extractHost(c.Request.Host)
|
||||
if host != "" && host != "localhost" && host != "127.0.0.1" && host != "::1" {
|
||||
host := sitecode.ExtractHost(c.Request.Host)
|
||||
if host != "" && !sitecode.IsLocalHost(host) {
|
||||
domain = host
|
||||
}
|
||||
}
|
||||
@@ -120,17 +118,6 @@ func firstNonEmpty(items ...string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func extractHost(rawHost string) string {
|
||||
rawHost = strings.TrimSpace(rawHost)
|
||||
if rawHost == "" {
|
||||
return ""
|
||||
}
|
||||
if host, _, err := net.SplitHostPort(rawHost); err == nil {
|
||||
return strings.Trim(host, "[]")
|
||||
}
|
||||
return strings.Trim(rawHost, "[]")
|
||||
}
|
||||
|
||||
// Login 短信验证码登录
|
||||
// @Summary 短信验证码登录
|
||||
// @Description 使用手机号和验证码登录
|
||||
|
||||
@@ -1,25 +1,14 @@
|
||||
package chat
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"hfb_sys/backend/internal/sitecode"
|
||||
"hfb_sys/backend/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func parseSiteCode(c *gin.Context) string {
|
||||
for _, val := range []string{
|
||||
c.Query("distribution_site_code"),
|
||||
c.Query("site_code"),
|
||||
c.GetHeader("X-Distribution-Site-Code"),
|
||||
c.GetHeader("X-Site-Code"),
|
||||
} {
|
||||
if trimmed := strings.TrimSpace(val); trimmed != "" {
|
||||
return trimmed
|
||||
}
|
||||
}
|
||||
return ""
|
||||
return sitecode.FromRequest(c)
|
||||
}
|
||||
|
||||
func (h *Handler) list(c *gin.Context, principal Principal) {
|
||||
|
||||
@@ -238,4 +238,3 @@ func TestCollectPaddleOCRJSONLTextSupportsPPOCRv6(t *testing.T) {
|
||||
t.Fatalf("candidates = %v, want 火爆出租-778群 as first candidate", candidates)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"hfb_sys/backend/internal/middleware"
|
||||
"hfb_sys/backend/internal/sitecode"
|
||||
"hfb_sys/backend/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -355,20 +356,13 @@ func (h *Handler) ListPublicSiteListings(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (h *Handler) GetPublicSiteInfo(c *gin.Context) {
|
||||
code := strings.TrimSpace(c.Query("code"))
|
||||
if code == "" {
|
||||
code = strings.TrimSpace(c.Query("site_code"))
|
||||
}
|
||||
if code == "" {
|
||||
code = strings.TrimSpace(c.GetHeader("X-Distribution-Site-Code"))
|
||||
}
|
||||
code := sitecode.FromQueryThenHeader(c)
|
||||
domain := strings.TrimSpace(c.Query("domain"))
|
||||
if code == "" && domain == "" {
|
||||
host := c.Request.Host
|
||||
if colon := strings.Index(host, ":"); colon != -1 {
|
||||
host = host[:colon]
|
||||
host := sitecode.ExtractHost(c.Request.Host)
|
||||
if host != "" && !sitecode.IsLocalHost(host) {
|
||||
domain = host
|
||||
}
|
||||
domain = host
|
||||
}
|
||||
info, err := h.service.GetPublicSiteInfo(c.Request.Context(), code, domain)
|
||||
if err != nil {
|
||||
@@ -382,14 +376,11 @@ func (h *Handler) GetPublicSiteInfo(c *gin.Context) {
|
||||
// 仅当域名属于系统中正常运行(active)的分销站点时返回 200,其余情况返回 404,
|
||||
// 防止任意外部未授权域名解析到该服务器刷爆 Let's Encrypt 证书申请配额。
|
||||
func (h *Handler) CheckDomain(c *gin.Context) {
|
||||
domain := strings.ToLower(strings.TrimSpace(c.Query("domain")))
|
||||
domain := sitecode.ExtractHost(c.Query("domain"))
|
||||
if domain == "" {
|
||||
c.String(http.StatusBadRequest, "domain required")
|
||||
return
|
||||
}
|
||||
if colon := strings.Index(domain, ":"); colon != -1 {
|
||||
domain = domain[:colon]
|
||||
}
|
||||
|
||||
info, err := h.service.GetPublicSiteInfo(c.Request.Context(), "", domain)
|
||||
if err != nil || info == nil || info.Status != "active" {
|
||||
|
||||
@@ -91,4 +91,3 @@ func TestNormalizeSceneListingScreenshotAndOperatingExpense(t *testing.T) {
|
||||
t.Fatalf("normalize operating_expense scene = %q, want operating-expense", got)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"hfb_sys/backend/internal/middleware"
|
||||
"hfb_sys/backend/internal/sitecode"
|
||||
"hfb_sys/backend/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -119,7 +120,7 @@ func parsePublicListQuery(c *gin.Context) PublicListQuery {
|
||||
MinSecretKD: parseOptionalFloat(c.Query("min_secret_kd")),
|
||||
MaxSecretKD: parseOptionalFloat(c.Query("max_secret_kd")),
|
||||
ResourceRanges: parseResourceRanges(c),
|
||||
DistributionSiteCode: strings.TrimSpace(firstNonEmpty(c.GetHeader("X-Distribution-Site-Code"), c.Query("distribution_site_code"), c.Query("site_code"))),
|
||||
DistributionSiteCode: sitecode.FromRequest(c),
|
||||
}
|
||||
if query.PageSize > 50 {
|
||||
query.PageSize = 50
|
||||
|
||||
@@ -3,9 +3,9 @@ package listing
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
filemodule "hfb_sys/backend/internal/modules/file"
|
||||
"hfb_sys/backend/internal/sitecode"
|
||||
"hfb_sys/backend/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -25,7 +25,7 @@ func (h *Handler) FindPublic(c *gin.Context) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
siteCode := strings.TrimSpace(firstNonEmpty(c.GetHeader("X-Distribution-Site-Code"), c.Query("distribution_site_code"), c.Query("site_code")))
|
||||
siteCode := sitecode.FromRequest(c)
|
||||
item, err := h.service.FindPublic(c.Request.Context(), id, siteCode)
|
||||
if err != nil {
|
||||
writeListingError(c, err)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package listing
|
||||
|
||||
import (
|
||||
"hfb_sys/backend/internal/sitecode"
|
||||
"hfb_sys/backend/pkg/response"
|
||||
"strings"
|
||||
|
||||
@@ -18,7 +19,7 @@ func (h *Handler) Create(c *gin.Context) {
|
||||
response.BadRequest(c, listingBindErrorMessage(err))
|
||||
return
|
||||
}
|
||||
siteCode := strings.TrimSpace(c.GetHeader("X-Distribution-Site-Code"))
|
||||
siteCode := sitecode.FromRequest(c)
|
||||
item, err := h.service.Create(c.Request.Context(), ownerID, req, siteCode)
|
||||
if err != nil {
|
||||
writeListingError(c, err)
|
||||
@@ -42,7 +43,7 @@ func (h *Handler) Update(c *gin.Context) {
|
||||
response.BadRequest(c, listingBindErrorMessage(err))
|
||||
return
|
||||
}
|
||||
item, err := h.service.Update(c.Request.Context(), ownerID, id, req, strings.TrimSpace(c.GetHeader("X-Distribution-Site-Code")))
|
||||
item, err := h.service.Update(c.Request.Context(), ownerID, id, req, sitecode.FromRequest(c))
|
||||
if err != nil {
|
||||
writeListingError(c, err)
|
||||
return
|
||||
@@ -103,7 +104,7 @@ func (h *Handler) ListMine(c *gin.Context) {
|
||||
response.Unauthorized(c, "缺少用户上下文")
|
||||
return
|
||||
}
|
||||
siteCode := strings.TrimSpace(c.GetHeader("X-Distribution-Site-Code"))
|
||||
siteCode := sitecode.FromRequest(c)
|
||||
items, err := h.service.ListMine(c.Request.Context(), ownerID, siteCode)
|
||||
if err != nil {
|
||||
writeListingError(c, err)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"hfb_sys/backend/internal/middleware"
|
||||
"hfb_sys/backend/internal/sitecode"
|
||||
"hfb_sys/backend/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -99,17 +100,7 @@ func (h *Handler) MarkRead(c *gin.Context) {
|
||||
}
|
||||
|
||||
func parseSiteCode(c *gin.Context) string {
|
||||
siteCode := c.Query("distribution_site_code")
|
||||
if siteCode == "" {
|
||||
siteCode = c.Query("site_code")
|
||||
}
|
||||
if siteCode == "" {
|
||||
siteCode = c.GetHeader("X-Distribution-Site-Code")
|
||||
}
|
||||
if siteCode == "" {
|
||||
siteCode = c.GetHeader("X-Site-Code")
|
||||
}
|
||||
return siteCode
|
||||
return sitecode.FromRequest(c)
|
||||
}
|
||||
|
||||
func currentUserID(c *gin.Context) (uint64, bool) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package order
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"hfb_sys/backend/internal/sitecode"
|
||||
"hfb_sys/backend/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -20,7 +21,7 @@ func (h *Handler) Create(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
if strings.TrimSpace(req.DistributionSiteCode) == "" {
|
||||
req.DistributionSiteCode = strings.TrimSpace(c.GetHeader("X-Distribution-Site-Code"))
|
||||
req.DistributionSiteCode = sitecode.FromRequest(c)
|
||||
}
|
||||
item, err := h.service.Create(c.Request.Context(), userID, req)
|
||||
if err != nil {
|
||||
@@ -37,7 +38,7 @@ func (h *Handler) List(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
page, pageSize := parsePagination(c)
|
||||
siteCode := strings.TrimSpace(firstNonEmpty(c.GetHeader("X-Distribution-Site-Code"), c.Query("distribution_site_code"), c.Query("site_code")))
|
||||
siteCode := sitecode.FromRequest(c)
|
||||
items, err := h.service.ListForUser(c.Request.Context(), userID, page, pageSize, siteCode)
|
||||
if err != nil {
|
||||
writeOrderError(c, err)
|
||||
@@ -53,7 +54,7 @@ func (h *Handler) ListSellerHandoffs(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
page, pageSize := parsePagination(c)
|
||||
siteCode := strings.TrimSpace(firstNonEmpty(c.GetHeader("X-Distribution-Site-Code"), c.Query("distribution_site_code"), c.Query("site_code")))
|
||||
siteCode := sitecode.FromRequest(c)
|
||||
items, err := h.service.ListSellerHandoffs(c.Request.Context(), userID, SellerHandoffQuery{
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
@@ -77,7 +78,7 @@ func (h *Handler) Detail(c *gin.Context) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
siteCode := strings.TrimSpace(firstNonEmpty(c.GetHeader("X-Distribution-Site-Code"), c.Query("distribution_site_code"), c.Query("site_code")))
|
||||
siteCode := sitecode.FromRequest(c)
|
||||
item, err := h.service.FindForUser(c.Request.Context(), userID, id, siteCode)
|
||||
if err != nil {
|
||||
writeOrderError(c, err)
|
||||
|
||||
@@ -927,4 +927,3 @@ func TestStartPaymentRoutesToDistributionSitePaymentChannel(t *testing.T) {
|
||||
t.Fatalf("Order B expected MerchantID=%s, got %s", defaultConfig.MerchantID, savedB.MerchantID)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ package wallet
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"hfb_sys/backend/internal/middleware"
|
||||
"hfb_sys/backend/internal/sitecode"
|
||||
"hfb_sys/backend/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -20,17 +20,7 @@ func NewHandler(service *Service) *Handler {
|
||||
}
|
||||
|
||||
func parseSiteCode(c *gin.Context) string {
|
||||
for _, val := range []string{
|
||||
c.Query("distribution_site_code"),
|
||||
c.Query("site_code"),
|
||||
c.GetHeader("X-Distribution-Site-Code"),
|
||||
c.GetHeader("X-Site-Code"),
|
||||
} {
|
||||
if trimmed := strings.TrimSpace(val); trimmed != "" {
|
||||
return trimmed
|
||||
}
|
||||
}
|
||||
return ""
|
||||
return sitecode.FromRequest(c)
|
||||
}
|
||||
|
||||
func (h *Handler) Balance(c *gin.Context) {
|
||||
|
||||
@@ -2,8 +2,8 @@ package withdrawal
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"hfb_sys/backend/internal/sitecode"
|
||||
"hfb_sys/backend/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -18,17 +18,7 @@ func NewHandler(service *Service) *Handler {
|
||||
}
|
||||
|
||||
func parseSiteCode(c *gin.Context) string {
|
||||
for _, val := range []string{
|
||||
c.Query("distribution_site_code"),
|
||||
c.Query("site_code"),
|
||||
c.GetHeader("X-Distribution-Site-Code"),
|
||||
c.GetHeader("X-Site-Code"),
|
||||
} {
|
||||
if trimmed := strings.TrimSpace(val); trimmed != "" {
|
||||
return trimmed
|
||||
}
|
||||
}
|
||||
return ""
|
||||
return sitecode.FromRequest(c)
|
||||
}
|
||||
|
||||
// ========== 用户端接口 ==========
|
||||
|
||||
@@ -95,29 +95,29 @@ func (r *Repository) toDetailDTO(ctx context.Context, w model.WithdrawalRequest)
|
||||
DistributionSiteName: siteName,
|
||||
DistributionSiteCode: siteCode,
|
||||
UserNickname: user.Nickname,
|
||||
UserPhone: user.Phone,
|
||||
AmountCent: w.AmountCent,
|
||||
FeeCent: w.FeeCent,
|
||||
ActualAmountCent: w.ActualAmountCent,
|
||||
PaymentAccountID: w.PaymentAccountID,
|
||||
AccountType: w.AccountType,
|
||||
AccountName: w.AccountName,
|
||||
AccountNo: fullAccountNo,
|
||||
BankName: w.BankName,
|
||||
BankBranch: w.BankBranch,
|
||||
CertificateURLs: certificateURLs,
|
||||
Status: w.Status,
|
||||
ReviewedBy: w.ReviewedBy,
|
||||
ReviewedByName: reviewedByName,
|
||||
ReviewedAt: w.ReviewedAt,
|
||||
ReviewRemark: w.ReviewRemark,
|
||||
PaidBy: w.PaidBy,
|
||||
PaidByName: paidByName,
|
||||
PaidAt: w.PaidAt,
|
||||
PaymentProofURL: w.PaymentProofURL,
|
||||
PaymentRemark: w.PaymentRemark,
|
||||
CreatedAt: w.CreatedAt,
|
||||
UpdatedAt: w.UpdatedAt,
|
||||
UserPhone: user.Phone,
|
||||
AmountCent: w.AmountCent,
|
||||
FeeCent: w.FeeCent,
|
||||
ActualAmountCent: w.ActualAmountCent,
|
||||
PaymentAccountID: w.PaymentAccountID,
|
||||
AccountType: w.AccountType,
|
||||
AccountName: w.AccountName,
|
||||
AccountNo: fullAccountNo,
|
||||
BankName: w.BankName,
|
||||
BankBranch: w.BankBranch,
|
||||
CertificateURLs: certificateURLs,
|
||||
Status: w.Status,
|
||||
ReviewedBy: w.ReviewedBy,
|
||||
ReviewedByName: reviewedByName,
|
||||
ReviewedAt: w.ReviewedAt,
|
||||
ReviewRemark: w.ReviewRemark,
|
||||
PaidBy: w.PaidBy,
|
||||
PaidByName: paidByName,
|
||||
PaidAt: w.PaidAt,
|
||||
PaymentProofURL: w.PaymentProofURL,
|
||||
PaymentRemark: w.PaymentRemark,
|
||||
CreatedAt: w.CreatedAt,
|
||||
UpdatedAt: w.UpdatedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
// Package sitecode 统一解析请求中的分销站点编码。
|
||||
//
|
||||
// 此前各业务模块(auth/order/wallet/chat/notification/withdrawal/listing/distribution)
|
||||
// 各自内联解析,优先级和 TrimSpace 处理不一致,且对旧头 X-Site-Code 的支持参差不齐。
|
||||
// 本包收敛为两个入口:
|
||||
//
|
||||
// - FromRequest:常规业务接口使用。SPA 前端(frontend/src/shared/api/client.ts)
|
||||
// 会为每个请求统一注入 X-Distribution-Site-Code 头,因此头是权威来源;
|
||||
// query 参数与旧头仅作为非 SPA 调用(脚本、排障)的兜底。
|
||||
// - FromQueryThenHeader:仅用于 GET /distribution/site-info 站点探测。
|
||||
// SPA 初始化探测新站点时会话头尚未建立,此时显式 query 参数必须压过会话头。
|
||||
package sitecode
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// HeaderName 是前端统一注入的权威站点编码请求头。
|
||||
const HeaderName = "X-Distribution-Site-Code"
|
||||
|
||||
// LegacyHeaderName 是历史版本使用的站点编码请求头,仅作兜底兼容。
|
||||
const LegacyHeaderName = "X-Site-Code"
|
||||
|
||||
// FromRequest 按权威优先级解析站点编码:
|
||||
// X-Distribution-Site-Code 头 → X-Site-Code 旧头 → distribution_site_code / site_code query。
|
||||
// 所有来源均做 TrimSpace,返回空串表示主站。
|
||||
func FromRequest(c *gin.Context) string {
|
||||
return firstNonEmpty(
|
||||
c.GetHeader(HeaderName),
|
||||
c.GetHeader(LegacyHeaderName),
|
||||
c.Query("distribution_site_code"),
|
||||
c.Query("site_code"),
|
||||
)
|
||||
}
|
||||
|
||||
// FromQueryThenHeader 仅用于站点探测接口(GET /distribution/site-info):
|
||||
// 显式 query 参数优先于会话头。SPA 探测新站点时会话头里还是上一个站点的编码,
|
||||
// 必须让 query 压过它,否则从主站跳转到分站时会探测到错误站点。
|
||||
func FromQueryThenHeader(c *gin.Context) string {
|
||||
return firstNonEmpty(
|
||||
c.Query("code"),
|
||||
c.Query("site_code"),
|
||||
c.Query("distribution_site_code"),
|
||||
c.GetHeader(HeaderName),
|
||||
c.GetHeader(LegacyHeaderName),
|
||||
)
|
||||
}
|
||||
|
||||
// ExtractHost 从 HTTP Host(可能带端口、IPv6 方括号)中提取纯主机名,小写化。
|
||||
func ExtractHost(rawHost string) string {
|
||||
rawHost = strings.TrimSpace(rawHost)
|
||||
if rawHost == "" {
|
||||
return ""
|
||||
}
|
||||
var host string
|
||||
if h, _, err := net.SplitHostPort(rawHost); err == nil {
|
||||
host = h
|
||||
} else {
|
||||
host = rawHost
|
||||
}
|
||||
return strings.ToLower(strings.Trim(host, "[]"))
|
||||
}
|
||||
|
||||
// IsLocalHost 判断主机名是否属于本地开发地址(不作为站点域名解析)。
|
||||
func IsLocalHost(host string) bool {
|
||||
return host == "localhost" || host == "127.0.0.1" || host == "::1"
|
||||
}
|
||||
|
||||
func firstNonEmpty(values ...string) string {
|
||||
for _, v := range values {
|
||||
if trimmed := strings.TrimSpace(v); trimmed != "" {
|
||||
return trimmed
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package sitecode
|
||||
|
||||
import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func newTestContext(method, target string, headers map[string]string) *gin.Context {
|
||||
gin.SetMode(gin.TestMode)
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
req := httptest.NewRequest(method, target, nil)
|
||||
for k, v := range headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
c.Request = req
|
||||
return c
|
||||
}
|
||||
|
||||
func TestFromRequest(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
target string
|
||||
header map[string]string
|
||||
want string
|
||||
}{
|
||||
{name: "仅头", target: "/api/listings", header: map[string]string{HeaderName: "site_a"}, want: "site_a"},
|
||||
{name: "旧头兜底", target: "/api/wallet/balance", header: map[string]string{LegacyHeaderName: "site_b"}, want: "site_b"},
|
||||
{name: "query兜底", target: "/api/wallet/balance?distribution_site_code=site_c", header: nil, want: "site_c"},
|
||||
{name: "短query兜底", target: "/api/orders?site_code=site_d", header: nil, want: "site_d"},
|
||||
{name: "头优先于query", target: "/api/orders?site_code=query_site", header: map[string]string{HeaderName: "header_site"}, want: "header_site"},
|
||||
{name: "权威头优先于旧头", target: "/api/chats", header: map[string]string{HeaderName: "new_site", LegacyHeaderName: "old_site"}, want: "new_site"},
|
||||
{name: "空白字符修剪", target: "/api/orders?site_code=%20%20site_e%20%20", header: nil, want: "site_e"},
|
||||
{name: "主站为空", target: "/api/orders", header: nil, want: ""},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got := FromRequest(newTestContext("GET", tc.target, tc.header))
|
||||
if got != tc.want {
|
||||
t.Fatalf("FromRequest() = %q, want %q", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromQueryThenHeader(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
target string
|
||||
header map[string]string
|
||||
want string
|
||||
}{
|
||||
{name: "code参数优先", target: "/distribution/site-info?code=probe_site", header: map[string]string{HeaderName: "session_site"}, want: "probe_site"},
|
||||
{name: "site_code参数优先", target: "/distribution/site-info?site_code=probe2", header: map[string]string{HeaderName: "session"}, want: "probe2"},
|
||||
{name: "无query时回落头", target: "/distribution/site-info", header: map[string]string{HeaderName: "session"}, want: "session"},
|
||||
{name: "全空", target: "/distribution/site-info", header: nil, want: ""},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got := FromQueryThenHeader(newTestContext("GET", tc.target, tc.header))
|
||||
if got != tc.want {
|
||||
t.Fatalf("FromQueryThenHeader() = %q, want %q", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractHost(t *testing.T) {
|
||||
cases := []struct {
|
||||
raw string
|
||||
want string
|
||||
}{
|
||||
{raw: "shop.example.com:8080", want: "shop.example.com"},
|
||||
{raw: "shop.example.com", want: "shop.example.com"},
|
||||
{raw: "Shop.Example.COM", want: "shop.example.com"},
|
||||
{raw: "[::1]:5189", want: "::1"},
|
||||
{raw: " shop.example.com ", want: "shop.example.com"},
|
||||
{raw: "", want: ""},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
if got := ExtractHost(tc.raw); got != tc.want {
|
||||
t.Errorf("ExtractHost(%q) = %q, want %q", tc.raw, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsLocalHost(t *testing.T) {
|
||||
for _, local := range []string{"localhost", "127.0.0.1", "::1"} {
|
||||
if !IsLocalHost(local) {
|
||||
t.Errorf("IsLocalHost(%q) 应为 true", local)
|
||||
}
|
||||
}
|
||||
for _, remote := range []string{"shop.example.com", "0.0.0.0", ""} {
|
||||
if IsLocalHost(remote) {
|
||||
t.Errorf("IsLocalHost(%q) 应为 false", remote)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user