Documentation
¶
Index ¶
- Constants
- Variables
- func HTTPTraceEnabled() bool
- func HeadString(b []byte, n int) string
- func Ptr[T any](v T) *T
- func SetHTTPTraceEnabled(enabled bool)
- func TokenSuffix(s string) string
- type APIKey
- type AccessTokenCache
- type AuthRetryEvent
- type BasicAuth
- type CacheItem
- type Configuration
- type IAuth
- type ISO8601Time
- type Logger
- type ServerConfiguration
- type ServerConfigurations
- type ServerVariable
- type TokenCache
- type TokenRefreshEvent
Constants ¶
const ( EventPhaseStart = "start" EventPhaseEnd = "end" )
EventPhase* 表示一次刷新事件的时序阶段,用于配对 start/end 两条日志。
Variables ¶
var ( // ContextServerIndex uses a server configuration from the index. ContextServerIndex = contextKey("serverIndex") // ContextOperationServerIndices uses a server configuration from the index mapping. ContextOperationServerIndices = contextKey("serverOperationIndices") // ContextServerVariables overrides a server configuration variables. ContextServerVariables = contextKey("serverVariables") // ContextOperationServerVariables overrides a server configuration variables using operation specific values. ContextOperationServerVariables = contextKey("serverOperationVariables") )
var ( OnTokenRefresh = func(TokenRefreshEvent) {} OnAuthRetry = func(AuthRetryEvent) {} )
OnTokenRefresh / OnAuthRetry 是可选的事件 hook。业务侧可在启动时(例如 main 里)替换为自定义实现以接入项目日志系统。默认实现为空,SDK 不产生任何日志副作用。
两个变量只应在程序启动时设置一次,不要在运行中并发修改(SDK 内部没有锁 保护)。如果业务侧确实需要运行中切换,应自行实现同步。
var DefaultClient = &http.Client{ Transport: SharedTransport, Timeout: 180 * time.Second, Jar: nil, }
DefaultClient 是基于 SharedTransport 的全局 HTTP 客户端,附带整体超时、Cookie 管理和重定向策略
var LongTimeHttpClient = &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, }, Timeout: 10 * time.Minute, Jar: nil, }
var MarketplaceMap = map[string]string{
"CA": "A2EUQ1WTGCTBG2",
"US": "ATVPDKIKX0DER",
"MX": "A1AM78C64UM0Y8",
"BR": "A2Q3Y263D00KWC",
"IE": "A28R8C7NBKEWEA",
"ES": "A1RKKUPIHCS9HS",
"UK": "A1F83G8C2ARO7P",
"FR": "A13V1IB3VIYZZH",
"BE": "AMEN7PMS3EDWL",
"NL": "A1805IZSGTT6HS",
"DE": "A1PA6795UKMFR9",
"IT": "APJ6JRA9NG5V4",
"SE": "A2NODRKZP88ZB9",
"ZA": "AE08WJ6YKNBMC",
"PL": "A1C3SOZRARQ6R3",
"EG": "ARBP9OOSHTCHU",
"TR": "A33AVAJ2PDY3EV",
"SA": "A17E79C6D8DWNP",
"AE": "A2VIGQ35RCS4UG",
"IN": "A21TJRUUN4KGV",
"SG": "A19VAU5U5O7RUS",
"AU": "A39IBJ37TRP1C6",
"JP": "A1VC38T7YXB528",
}
DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, }).DialContext, MaxIdleConns: 100, MaxIdleConnsPerHost: 10, MaxConnsPerHost: 2000, IdleConnTimeout: 10 * time.Second, TLSHandshakeTimeout: 30 * time.Second, ExpectContinueTimeout: 30 * time.Second, ResponseHeaderTimeout: 30 * time.Second, MaxResponseHeaderBytes: 1 << 20, DisableKeepAlives: false, DisableCompression: false, TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, ForceAttemptHTTP2: true, }
SharedTransport 是一个全局可复用的 HTTP Transport,配置了连接池、超时和 TLS 等参数
Functions ¶
func HTTPTraceEnabled ¶
func HTTPTraceEnabled() bool
func HeadString ¶
HeadString 返回 b 的前 n 字节作为字符串。b 短于 n 时直接全部返回。 专用于把 HTTP 响应 body 前若干字节写入诊断事件,既保留诊断价值又避免 日志膨胀 / 误把长 body 的敏感部分打出去。
func SetHTTPTraceEnabled ¶
func SetHTTPTraceEnabled(enabled bool)
SetHTTPTraceEnabled 控制 SDK 是否记录 HTTP 请求与响应摘要。
func TokenSuffix ¶
TokenSuffix 返回字符串的最后 8 个字符,前面加 "..."。用于安全地把 refresh_token / access_token 写入日志,避免泄漏完整凭据。 对不足 8 位的字符串(异常或空值)返回固定占位符。
Types ¶
type APIKey ¶
APIKey provides API key based authentication to a request passed via context using ContextAPIKey
type AccessTokenCache ¶
func (*AccessTokenCache) Get ¶
func (s *AccessTokenCache) Get(key any) string
func (*AccessTokenCache) Invalidate ¶
func (s *AccessTokenCache) Invalidate(key any)
Invalidate 移除给定 refresh_token 对应的缓存条目。 当下游接口明确告知"access token 已过期"时(缓存的 ExpiresAt 与 Amazon 服务端判定不一致的偶发场景——时钟偏差/节点缓存),调用方应显式 Invalidate, 让下一次 Get 返回空,触发 singleflight 重新刷新。
注意:名字不叫 Delete 是为了避免和嵌入的 sync.Map.Delete 方法产生歧义/误用。
func (*AccessTokenCache) InvalidateIfMatch ¶
func (s *AccessTokenCache) InvalidateIfMatch(key any, failedToken string)
InvalidateIfMatch 仅当缓存中当前的 AccessToken 仍等于 failedToken 时才删除, 专用于多 goroutine 并发重试的场景:
t0 A 用 T1 请求 -> 401 t1 A Invalidate,singleflight 刷出 T2,写入 cache t2 B 用 T1 请求 -> 401 (B 是在 A 刷新前发出去的,返回慢了) t3 B 若无脑 Invalidate,会把 A 刚写的 T2 删掉,触发多余的一次 LwA 刷新
改用 InvalidateIfMatch(key, T1) 后:t3 时 cache 里已是 T2,failedToken=T1 不匹配,不会误删;B 紧跟着的 acquireAccessToken 从 cache 直接命中 T2 复用。
对 Amazon 配额压力不大,但能让"token 自然过期那一刻"的刷新次数收敛到 1 次。
DEBUG 日志区分三种结果,便于排查"并发竞态是否真的发生":
- hit:成功删除了失败 token
- skipped-newer-token:缓存里已经是别的 goroutine 刷出来的新 token, 本方法保护了新 token 不被误删(就是避免冗余刷新的关键)
- miss:key 不存在或值类型异常
type AuthRetryEvent ¶
type AuthRetryEvent struct {
Service string
RefreshTokenSuffix string
Method string
URL string
// FirstStatus / FirstBodyHead 首次响应的状态码与 body 前 256 字节,
// 便于诊断 shouldRetryAuthExpired 匹配了哪条规则。
FirstStatus int
FirstBodyHead string
// FailedAccessTokenSuffix 首次请求用的 token 后 8 位。
FailedAccessTokenSuffix string
// 以下字段表示"重试本身的结果":
// - RetrySkipped 非空:未执行重试,原因如 "body-not-cloneable";
// 此时 RetryStatus/RetryErr 均为零值。
// - RetrySkipped 空且 RetryErr 非 nil:网络错误,重试请求未拿到响应。
// - RetrySkipped 空且 RetryStatus != 0:重试已经拿到 HTTP 响应。
RetrySkipped string
RetryStatus int
RetryErr error
}
AuthRetryEvent 描述一次 SDK 层的 401/403 兜底重试。
触发条件:shouldRetryAuthExpired 命中(SDK 判定是 access_token 被 Amazon 拒绝的瞬时错误),SDK 将清缓存、重刷 token、重发一次原请求。
type BasicAuth ¶
type BasicAuth struct {
UserName string `json:"userName,omitempty"`
Password string `json:"password,omitempty"`
}
BasicAuth provides basic http authentication to a request passed via context using ContextBasicAuth
type Configuration ¶
type Configuration struct {
Host string `json:"host,omitempty"`
Scheme string `json:"scheme,omitempty"`
DefaultHeader map[string]string `json:"defaultHeader,omitempty"`
UserAgent string `json:"userAgent,omitempty"`
Debug bool `json:"debug,omitempty"`
Servers ServerConfigurations
OperationServers map[string]ServerConfigurations
HTTPClient *http.Client
}
Configuration stores the configuration of the API client
func NewConfiguration ¶
func NewConfiguration(iAuth IAuth) *Configuration
NewConfiguration returns a new Configuration object
func (*Configuration) AddDefaultHeader ¶
func (c *Configuration) AddDefaultHeader(key string, value string)
AddDefaultHeader adds a new HTTP header to the default header in the request
func (*Configuration) ServerURLWithContext ¶
ServerURLWithContext returns a new server URL given an endpoint
type ISO8601Time ¶
func (*ISO8601Time) MarshalJSON ¶
func (t *ISO8601Time) MarshalJSON() ([]byte, error)
func (*ISO8601Time) Scan ¶
func (t *ISO8601Time) Scan(v any) error
func (ISO8601Time) String ¶
func (t ISO8601Time) String() string
func (*ISO8601Time) UnmarshalJSON ¶
func (t *ISO8601Time) UnmarshalJSON(data []byte) error
type Logger ¶
type Logger interface {
Debug(msg string, fields ...any)
Info(msg string, fields ...any)
Warn(msg string, fields ...any)
Error(msg string, fields ...any)
}
Logger 是 SDK 内部使用的日志抽象。
SDK 刻意不直接依赖 slog/logrus/zap 等具体库,避免把调用方绑死在某个 logger 生态上。业务侧可以在启动时提供一个实现,把 SDK 内部的细粒度诊断日志 (网络错误、RDT 透传、cache 失效行为等)统一路由到自己的日志系统。
职责划分:
- OnTokenRefresh / OnAuthRetry 是**事件 hook**,强类型结构体,适合做 指标统计 / 告警路由等。
- Logger 是**诊断日志**,松散 kv,用来记录事件 hook 未覆盖的边角情况。
两者正交,业务侧各自按需注册。
方法签名参考 slog.Logger:fields 是变长 any,每两个一组 (key, value); 奇数个或 key 非字符串时,Adapter 实现应自行决定如何处理(通常是丢弃或 塞到 "?key" 里)。
var DefaultLogger Logger = noopLogger{}
DefaultLogger 是 SDK 包级日志入口,默认 no-op。业务侧可在进程启动时替换:
pkg.DefaultLogger = myAdapter{...}
只应在程序启动阶段设置一次,运行期并发写没有锁保护。
type ServerConfiguration ¶
type ServerConfiguration struct {
URL string
Description string
Variables map[string]ServerVariable
}
ServerConfiguration stores the information about a server
type ServerConfigurations ¶
type ServerConfigurations []ServerConfiguration
ServerConfigurations stores multiple ServerConfiguration items
type ServerVariable ¶
ServerVariable stores the information about a server variable
type TokenCache ¶
type TokenRefreshEvent ¶
type TokenRefreshEvent struct {
// Service 触发方,固定取值:"advertising" / "selling_partner"。
Service string
// RefreshTokenSuffix 已脱敏的 refresh_token 最后 8 位,用于关联同一 seller
// 的多次事件,安全地写入日志。
RefreshTokenSuffix string
// Reason 触发本次刷新的上游原因:
// "cache-miss" 首次或 token 自然临近过期
// "401-retry" 前一次业务请求被 Amazon 判为无效 token,强制刷新重试
Reason string
// Phase 当前处于刷新的哪个阶段:EventPhaseStart / EventPhaseEnd。
Phase string
// Success 是否成功;为 false 时 Err 必定非 nil。
Success bool
// Duration 从发起 HTTP 到收到响应的耗时。
Duration time.Duration
// AccessTokenSuffix 新 access_token 最后 8 位(仅成功时)。
AccessTokenSuffix string
// ExpiresAt 新 token 的预期过期时刻(仅成功时)。
ExpiresAt time.Time
// Err 失败原因(仅失败时)。
Err error
}
TokenRefreshEvent 描述一次"真正发生的"LwA access_token 换取过程。
发送时机:singleflight 回调进入 HTTP 请求阶段时就算一次事件;cache 命中、 singleflight 双检直接复用别人结果的场景不发(避免淹没日志)。
一次刷新按时序会收到两个事件:Phase=EventPhaseStart / EventPhaseEnd。 末尾事件通过 Success 字段区分成功失败,便于外部 logger 做 start+duration 对齐。