From ba1a909d49ac7ef681fd3f3e1a6533e9b6cc40b2 Mon Sep 17 00:00:00 2001 From: Star Date: Sat, 18 Jul 2026 18:45:24 +0800 Subject: [PATCH] =?UTF-8?q?fix(service):=20=E5=AF=B9=E9=BD=90=E6=96=B0?= =?UTF-8?q?=E7=89=88=E6=9C=8D=E5=8A=A1=E5=8F=91=E7=8E=B0=E4=B8=8E=E7=A8=B3?= =?UTF-8?q?=E5=AE=9A=E4=BE=9D=E8=B5=96=E9=93=BE=EF=BC=88by=20AI=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++ TEST.md | 12 +++++--- go.mod | 14 ++++----- go.sum | 38 +++++++++++++---------- handler.go | 8 ++--- proxy.go | 5 ++-- request.go | 8 ++--- server.go | 85 ++++++++++++++++++++++++++++------------------------ 8 files changed, 100 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb83ac1..4c913f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG - go/service +## v1.5.21 (2026-07-18) +- **依赖校验修复**: 升级 `discover` 至 `v1.5.7`、`redis` 至 `v1.5.11`,并使用稳定版 `redigo v1.9.3`。 +- **依赖对齐**: 升级 `cast` 至 `v1.5.4`、`crypto` 至 `v1.5.4`、`encoding` 至 `v1.5.5`、`starter` 至 `v1.5.6`。 +- **Discover API 对齐**: 服务注册与代理调用改用新版包级 Discover API;调用配置转换为统一的协议、超时和 Token 字符串格式。 +- **Header 命名对齐**: 内部引用统一采用 `RequestId`、`SessionId`、`DeviceId`、`UserId`、`ClientIp` Go 命名。 + ## v1.5.20 (2026-06-22) - **Client Key 应答头条件化**: - `Device-Id` / `Session-Id` 仅当请求头未携带时才写入应答头,避免客户端已持有 ID 时重复返回。 diff --git a/TEST.md b/TEST.md index ec5555f..8a0f1d0 100644 --- a/TEST.md +++ b/TEST.md @@ -1,10 +1,14 @@ # Service Module Test Report +## v1.5.21 验证 +- `go list -m all`:模块图使用 `discover v1.5.7`、`redis v1.5.11` 与稳定版 `redigo v1.9.3`。 +- `go test -v ./...` 与 `go test -bench=. ./...` 全部通过。 + ## 性能测试 (Benchmark) -- 测试日期: 2026-06-22 -- 版本: v1.5.20 -- 指标: `BenchmarkRouting`: **5394 ns/op** -- 环境: Darwin / Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz +- 测试日期: 2026-07-18 +- 版本: v1.5.21 +- 指标: `BenchmarkRouting`: **2382 ns/op** +- 环境: Darwin / Apple M3 Max ## 单元测试覆盖 (Unit Test) - [x] `TestServeHTTP`: 基础请求与响应 diff --git a/go.mod b/go.mod index 9e86677..9a21423 100644 --- a/go.mod +++ b/go.mod @@ -3,17 +3,17 @@ module apigo.cc/go/service go 1.25.0 require ( - apigo.cc/go/cast v1.5.3 + apigo.cc/go/cast v1.5.4 apigo.cc/go/config v1.5.3 - apigo.cc/go/discover v1.5.3 + apigo.cc/go/discover v1.5.7 apigo.cc/go/file v1.5.5 apigo.cc/go/http v1.5.3 apigo.cc/go/id v1.5.6 apigo.cc/go/jsmod v1.5.3 apigo.cc/go/log v1.5.8 - apigo.cc/go/redis v1.5.10 + apigo.cc/go/redis v1.5.11 apigo.cc/go/safe v1.5.2 - apigo.cc/go/starter v1.5.5 + apigo.cc/go/starter v1.5.6 apigo.cc/go/timer v1.5.0 apigo.cc/go/watch v1.5.2 github.com/gorilla/websocket v1.5.3 @@ -21,13 +21,13 @@ require ( ) require ( - apigo.cc/go/crypto v1.5.3 // indirect - apigo.cc/go/encoding v1.5.4 // indirect + apigo.cc/go/crypto v1.5.4 // indirect + apigo.cc/go/encoding v1.5.5 // indirect apigo.cc/go/rand v1.5.3 // indirect apigo.cc/go/shell v1.5.4 // indirect github.com/fsnotify/fsnotify v1.10.1 // indirect github.com/gobwas/glob v0.2.3 // indirect - github.com/gomodule/redigo v2.0.0+incompatible // indirect + github.com/gomodule/redigo v1.9.3 // indirect golang.org/x/crypto v0.52.0 // indirect golang.org/x/sys v0.45.0 // indirect golang.org/x/text v0.37.0 // indirect diff --git a/go.sum b/go.sum index 4718c4d..f784981 100644 --- a/go.sum +++ b/go.sum @@ -1,51 +1,57 @@ -apigo.cc/go/cast v1.5.3 h1:jk6VX0rGFhjKtfPhsaV6IKYpiGmORRk9qPTtuNS53tw= -apigo.cc/go/cast v1.5.3/go.mod h1:GMjjrYn93tWat1U409G7h1jR3ejfLLI7r0efBo9Sbd4= +apigo.cc/go/cast v1.5.4 h1:OH5Vkrc1K19wuazf9VecjwwMwKDFgLQkI3UvwB4umcs= +apigo.cc/go/cast v1.5.4/go.mod h1:GMjjrYn93tWat1U409G7h1jR3ejfLLI7r0efBo9Sbd4= apigo.cc/go/config v1.5.3 h1:peq1FM2xO+vzPHJf8Dwg3DXm8PtFQMfTFKQj6fpoG7A= apigo.cc/go/config v1.5.3/go.mod h1:ZiOAjWa1mQIzszaJZN+kO6YU4GXreng+NxkcK/TAkqQ= -apigo.cc/go/crypto v1.5.3 h1:2JUHC2cgR2zrnn36EzwkUAdxmmTXAA/8yTNo+2X1mPE= -apigo.cc/go/crypto v1.5.3/go.mod h1:PheYKHEXmoEFI1AK5PpY1borQWcRlkkSaWncT3cWbhE= -apigo.cc/go/discover v1.5.3 h1:WW1A7qReYytebETDb5MhVRPmT10KReGM4QbPTfqS/iw= -apigo.cc/go/discover v1.5.3/go.mod h1:rylFiGvfNro090rGtlc9K31KATn6WZbnn1Fk2AbQZEU= -apigo.cc/go/encoding v1.5.4 h1:Fk8TrveZATyy8SHukC4ZiqdTSp+QIfsRHtt55xmMK7w= -apigo.cc/go/encoding v1.5.4/go.mod h1:dShEsZ3gKqBINz7TSOYf4e7/fBCqCY9VzlenoGUQUFM= +apigo.cc/go/crypto v1.5.4 h1:7rFcF9Mns+7BIB13lystvLVsAeYapKsrD26KOrQq2Zk= +apigo.cc/go/crypto v1.5.4/go.mod h1:PheYKHEXmoEFI1AK5PpY1borQWcRlkkSaWncT3cWbhE= +apigo.cc/go/discover v1.5.7 h1:wb2hXr+6mGxZ+yjOuTNzeLSZ8tNaPvn+dl1AuedPRm0= +apigo.cc/go/discover v1.5.7/go.mod h1:Vg41wYA5+M7t883imlQEOwdeUPZPoNrzDWVshum7KYo= +apigo.cc/go/encoding v1.5.5 h1:kduNLWQgtcQqHYobOuu1djbgg8LedkGOe8f18ZMfqzs= +apigo.cc/go/encoding v1.5.5/go.mod h1:Big9q1Zwy4071dXtnrQ3SJDzfa/G7/A60KE/5+M//P8= apigo.cc/go/file v1.5.5 h1:/+HmDumLu6Qk2KuQL63M9lpgzHTDL+QJ8dStOl7e9gs= apigo.cc/go/file v1.5.5/go.mod h1:xRVNhctvqOKeBemmcRW/BQfgkc3B+vT/UZVdSc7duUo= apigo.cc/go/http v1.5.3 h1:nvJh9bqPPcPRv6p8WEw7bJAd0UC+r2zvQA8/QioVLTQ= apigo.cc/go/http v1.5.3/go.mod h1:cFrPK61y9f1PrsNSJscZT/QVOgkT15o9OP7O8cuMb8Q= -apigo.cc/go/id v1.5.5 h1:fQXfb2WZ4hEtzXkpb9w9o8AOcTZ44fYQfTV6iZ49l8o= -apigo.cc/go/id v1.5.5/go.mod h1:hCTQq+KC1ALWe1FpPERf+W4B6FSulg9FAgOUJDDySiY= +apigo.cc/go/id v1.5.6 h1:Z3PPp8H8FgNHMwHerxtT2GgstueDv4aCDnUUCoQZoFQ= +apigo.cc/go/id v1.5.6/go.mod h1:HcJK691qfBPzvQ/lt8bo/incKUFtG5vENX/rDEgzJh0= apigo.cc/go/jsmod v1.5.3 h1:S3W317bH0QV2NMeRO1E0v6ySIBOfMWYv/NuQJbvqKWU= apigo.cc/go/jsmod v1.5.3/go.mod h1:bmyeZtOAP/j5am+YRnaiM89smysK24K7ebk0koFtsSw= apigo.cc/go/log v1.5.8 h1:/IYtGPWhRjT3OayylDIphkWZIQbpLjqVeSnFEiD3Dy0= apigo.cc/go/log v1.5.8/go.mod h1:HfFPANMYxJx197SSTXB21Pgxcz/gGqPP8nlSErgd5WE= apigo.cc/go/rand v1.5.3 h1:O4bPIwyaOWEBCr0nL9A4G4qG48AqiGTCzfPeckm3Ius= apigo.cc/go/rand v1.5.3/go.mod h1:q1BTFkY/cXE229dDD5Q22lF7T0DoKPV6xAu+6bCrDH4= -apigo.cc/go/redis v1.5.9 h1:h77XPjQWcIDgxrtwjtS/gwT6PS5nSk6/x785t0OMlbY= -apigo.cc/go/redis v1.5.9/go.mod h1:YZRDLA3gWw9LAc4Z/4GrDEy8eMDMdDPDA0iqSEAu1fE= +apigo.cc/go/redis v1.5.11 h1:r/kiY3EUD+3YwTd+zMZaRD7eOQZEIvSJwAVnzG96zoQ= +apigo.cc/go/redis v1.5.11/go.mod h1:sCzxIWN+nNIRvR5ePaHsP19hjR52NPfXsq7L1c6A5ec= apigo.cc/go/safe v1.5.2 h1:EnuEOW/SGwf/5A0nw9LnqfKJE071+TIc6ez8HI9R9Lg= apigo.cc/go/safe v1.5.2/go.mod h1:2GqCCLLGex4OAhdET3iBWm1R+LIYtmTrvHP8W0iESSw= apigo.cc/go/shell v1.5.4 h1:Kn6lP6I6d9U0hbyUjpKKFdFZ8RPo4vi4V6AYW8YFzrc= apigo.cc/go/shell v1.5.4/go.mod h1:FdZWUrcXHGJXo725oSyHqAeFoX0E9yY3PDhrz9hujgY= -apigo.cc/go/starter v1.5.5 h1:4ST02o4qP8IIekxtd9Jhx5RHTrSGXtVQUguSIXV0iWc= -apigo.cc/go/starter v1.5.5/go.mod h1:WAGhdtmZdpP1Jn/z0pCqHwpTbqqaFhm5OqH7QVtcanY= +apigo.cc/go/starter v1.5.6 h1:hcZbR/70q0XW8xZII8BnGDmIomus//+8sWxGqluyj0U= +apigo.cc/go/starter v1.5.6/go.mod h1:abqfSu+lUz/FySn1VxjT8QeAa3mfKo6WrP5xLddw7QE= apigo.cc/go/timer v1.5.0 h1:iPo/IQn+iuhBRI1/MR1txwZnamef/RBBfOiIlBiqkgk= apigo.cc/go/timer v1.5.0/go.mod h1:kOnqTTX+zA4AH7SfC+LpUm4ZvS+DVyWWMqul/V5QWJs= apigo.cc/go/watch v1.5.2 h1:zG56PD8Vml5gVJeo2yNuX9s6stOaIJRYqqKGqXK+xTU= apigo.cc/go/watch v1.5.2/go.mod h1:MW1XnI0MVyUZpRy590no1vrDT+U4y20L0UZW9/LgU+k= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= -github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/gomodule/redigo v1.9.3 h1:dNPSXeXv6HCq2jdyWfjgmhBdqnR6PRO3m/G05nvpPC8= +github.com/gomodule/redigo v1.9.3/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= diff --git a/handler.go b/handler.go index 979b5fc..1c25bae 100644 --- a/handler.go +++ b/handler.go @@ -30,10 +30,10 @@ func (rh *RouteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { defer atomic.AddInt64(&rh.webRequestingNum, -1) tracker := timer.Start() - requestId := r.Header.Get(discover.HeaderRequestID) + requestId := r.Header.Get(discover.HeaderRequestId) if requestId == "" { requestId = IDMaker.Get10Bytes14MPerSecond() - r.Header.Set(discover.HeaderRequestID, requestId) + r.Header.Set(discover.HeaderRequestId, requestId) } request := NewRequest(r) @@ -458,7 +458,7 @@ func (ws *WebServer) handleClientKeys(request *Request, response *Response) { }) } } - request.Request.Header.Set(discover.HeaderSessionID, sessionId) + request.Request.Header.Set(discover.HeaderSessionId, sessionId) if !hasRequestSessionId { response.Header().Set(ws.usedSessionIdKey, sessionId) } @@ -487,7 +487,7 @@ func (ws *WebServer) handleClientKeys(request *Request, response *Response) { }) } } - request.Request.Header.Set(discover.HeaderDeviceID, deviceId) + request.Request.Header.Set(discover.HeaderDeviceId, deviceId) if !hasRequestDeviceId { response.Header().Set(ws.usedDeviceIdKey, deviceId) } diff --git a/proxy.go b/proxy.go index 9794bf1..b646e85 100644 --- a/proxy.go +++ b/proxy.go @@ -1,6 +1,7 @@ package service import ( + "apigo.cc/go/discover" gohttp "apigo.cc/go/http" "apigo.cc/go/log" "fmt" @@ -172,12 +173,12 @@ func (ws *WebServer) processProxy(request *Request, response *Response, logger * copyResponse(res, response, logger) } else { // Discover 代理 - if ws.discoverer == nil { + if !ws.discoverStarted { logger.Error("proxy failed: Discoverer is not initialized") response.WriteHeader(http.StatusBadGateway) return true } - caller := ws.discoverer.NewCaller(request.Request, logger) + caller := discover.NewCaller(request.Request, logger) caller.NoBody = true res, _ := caller.ManualDoWithNode(request.Method, app, "", path, request.Body) copyResponse(res, response, logger) diff --git a/request.go b/request.go index d59aa55..4a949ed 100644 --- a/request.go +++ b/request.go @@ -188,22 +188,22 @@ func (r *Request) MakeUrl(path string) string { // DeviceId 获取设备 ID func (r *Request) DeviceId() string { - return r.Header().Get(discover.HeaderDeviceID) + return r.Header().Get(discover.HeaderDeviceId) } // SessionId 获取会话 ID func (r *Request) SessionId() string { - return r.Header().Get(discover.HeaderSessionID) + return r.Header().Get(discover.HeaderSessionId) } // SetUserId 设置用户 ID(传递给下游) func (r *Request) SetUserId(userId string) { - r.Header().Set(discover.HeaderUserID, userId) + r.Header().Set(discover.HeaderUserId, userId) } // ClientIp 获取真实 IP func (r *Request) ClientIp() string { - ip := r.Header().Get(discover.HeaderClientIP) + ip := r.Header().Get(discover.HeaderClientIp) if ip == "" { ip = r.Header().Get(discover.HeaderForwardedFor) } diff --git a/server.go b/server.go index 0ebfaed..e8df122 100644 --- a/server.go +++ b/server.go @@ -5,7 +5,6 @@ import ( "apigo.cc/go/discover" "apigo.cc/go/log" "apigo.cc/go/redis" - "apigo.cc/go/safe" "apigo.cc/go/starter" "apigo.cc/go/watch" "context" @@ -29,13 +28,13 @@ type staticType struct { } type WebServer struct { - Config ServiceConfig - server *http.Server - listener net.Listener - Addr string - useDiscover bool - discoverer *discover.Discoverer - logger *log.Logger + Config ServiceConfig + server *http.Server + listener net.Listener + Addr string + useDiscover bool + discoverStarted bool + logger *log.Logger // 运行时状态 serverId string @@ -146,16 +145,32 @@ func NewWebServer() *WebServer { injectObjects: make(map[reflect.Type]any), injectFunctions: make(map[reflect.Type]func() any), - usedSessionIdKey: "Session-ID", - usedDeviceIdKey: "Device-ID", - usedClientAppKey: "App", + usedSessionIdKey: "Session-ID", + usedDeviceIdKey: "Device-ID", + usedClientAppKey: "App", } return ws } -// SetDiscovererForTest 提供给测试用例使用的后门方法,用于模拟断开或重置服务发现 -func SetDiscovererForTest(d *discover.Discoverer) { - DefaultServer.discoverer = d +func makeDiscoverCallConfig(call CallConfig, fallbackTimeout int) string { + protocol := "http" + if call.SSL { + protocol = "https" + } else if call.Http2 { + protocol = "h2c" + } + parts := []string{protocol} + timeout := call.Timeout + if timeout <= 0 { + timeout = fallbackTimeout + } + if timeout > 0 { + parts = append(parts, fmt.Sprintf("%dms", timeout)) + } + if call.Token != "" { + parts = append(parts, call.Token) + } + return strings.Join(parts, ":") } // ApplyConfig 将 ServiceConfig 中的路由策略应用到内部的文件级策略中 @@ -395,30 +410,14 @@ func (ws *WebServer) Start(ctx context.Context, logger *log.Logger) error { ip := GetServerIp() discoverAddr := fmt.Sprintf("%s:%s", ip, port) - discConf := discover.Config{ - Weight: ws.Config.Weight, - CallRetryTimes: 10, - Calls: make(map[string]discover.CallConfig), - } - - if discConf.Weight <= 0 { - discConf.Weight = 100 + weight := ws.Config.Weight + if weight <= 0 { + weight = 100 } + calls := make(map[string]string, len(ws.Config.Calls)) for name, call := range ws.Config.Calls { - dc := discover.CallConfig{ - Http2: call.Http2, - SSL: call.SSL, - } - if call.Timeout > 0 { - dc.Timeout = time.Duration(call.Timeout) * time.Millisecond - } else if ws.Config.RedirectTimeout > 0 { - dc.Timeout = time.Duration(ws.Config.RedirectTimeout) * time.Millisecond - } - if call.Token != "" { - dc.Token = safe.NewSafeBuf([]byte(call.Token)) - } - discConf.Calls[name] = dc + calls[name] = makeDiscoverCallConfig(call, ws.Config.RedirectTimeout) } registry := ws.Config.Register @@ -427,8 +426,15 @@ func (ws *WebServer) Start(ctx context.Context, logger *log.Logger) error { } if registry != "" { - ws.discoverer = discover.Start(registry, appName, discoverAddr, logger, discConf) - if ws.discoverer != nil { + discover.Init() + discover.Config.Registry = registry + discover.Config.App = appName + discover.Config.Weight = weight + discover.Config.CallRetryTimes = 10 + discover.Config.Calls = calls + discover.SetLogger(logger) + ws.discoverStarted = discover.Start(discoverAddr) + if ws.discoverStarted { logger.Info("discover registered", "app", appName, "addr", discoverAddr) } } @@ -468,8 +474,9 @@ func (ws *WebServer) Stop(ctx context.Context) error { ws.shutdownHooks = nil ws.shutdownHooksLock.Unlock() - if ws.discoverer != nil { - ws.discoverer.Stop() + if ws.discoverStarted { + discover.Stop() + ws.discoverStarted = false } if ws.server != nil { if err := ws.server.Shutdown(ctx); err != nil {