feat: bump v2.0.1, add CLI help usage, support fast wildcard path matching in README and tests (by AI)

This commit is contained in:
AI Engineer 2026-05-13 00:49:29 +08:00
parent 0984b688be
commit e0a1329426
3 changed files with 56 additions and 2 deletions

View File

@ -11,7 +11,24 @@
- **服务发现原生集成**:与 `@go/discover` 无缝集成,支持基于服务名的直连与负载均衡。 - **服务发现原生集成**:与 `@go/discover` 无缝集成,支持基于服务名的直连与负载均衡。
- **生命周期接管**:由 `@go/starter` 接管,支持通过 `kill -SIGHUP` 触发本地全量重新同步。 - **生命周期接管**:由 `@go/starter` 接管,支持通过 `kill -SIGHUP` 触发本地全量重新同步。
## 配置模型 (Redis Hash) ## 路由匹配规则 (无需正则的高性能模式)
网关底层针对高并发场景深度优化,默认支持 O(1) 级别的哈希匹配和高性能前缀匹配,**极大程度地避免了正则表达式的性能开销**。
### 1. Host 域名自适应降级匹配
网关在匹配请求的 Host 时,遵循一套人性化的自动降级回退机制,确保最灵活的配置:
1. **精确域名+端口**: `aa.com:8080` (最高优先级)
2. **纯域名提取**: `aa.com` (能同时适配 `aa.com:8080``aa.com:80`)
3. **纯端口截获**: `:80``:8080` (匹配任意该端口的主机)
4. **全局通配符**: `*` 或空字符串 `""` (兜底拦截所有未匹配请求)
### 2. Path 路径极速前缀匹配
默认情况下,非正则路径是**精确绝对匹配**。为了取代高消耗的前缀正则,网关特别引入了 `/*` 高性能通配符:
- **精确匹配 (默认)**: `"Path": "/api"` 仅匹配完全等于 `/api` 的请求。
- **极速前缀匹配 (带 `/*`)**: `"Path": "/api/*"` 将匹配任何以 `/api/` 开头的请求,底层直接使用原生 `strings.HasPrefix` 剥离正则损耗。
- *路径截取映射*: 当配置 `{"Path": "/old/*", "ToPath": "/new/*"}` 时,请求 `/old/user/1` 会被极速映射为 `/new/user/1`
*注:只有当匹配规则需要提取复杂的动态参数(如中间段 `$1` 捕获)时,才建议使用正则匹配 `^/api/([a-z]+)/xxx`。*
Gateway 将配置存储在 Redis 的 Hash 结构中,并按照 **Host (域名)** 进行字段隔离,提升拉取效率和管理粒度。 Gateway 将配置存储在 Redis 的 Hash 结构中,并按照 **Host (域名)** 进行字段隔离,提升拉取效率和管理粒度。

View File

@ -35,6 +35,9 @@ func TestGateway(t *testing.T) {
service.Host("*").GET("/hello", func(req *service.Request) string { service.Host("*").GET("/hello", func(req *service.Request) string {
return "hello from backend, path: " + req.RequestURI return "hello from backend, path: " + req.RequestURI
}) })
service.Host("*").GET("/hello/world", func(req *service.Request) string {
return "hello from backend, path: " + req.RequestURI
})
asBackend := service.AsyncStart() asBackend := service.AsyncStart()
defer asBackend.Stop() defer asBackend.Stop()
@ -48,6 +51,7 @@ func TestGateway(t *testing.T) {
proxyRules := []service.ProxyRule{ proxyRules := []service.ProxyRule{
{Path: "^/api/(.*)$", ToApp: "test-backend", ToPath: "/$1"}, {Path: "^/api/(.*)$", ToApp: "test-backend", ToPath: "/$1"},
{Path: "/direct", ToApp: "test-backend", ToPath: "/hello"}, {Path: "/direct", ToApp: "test-backend", ToPath: "/hello"},
{Path: "/v2/*", ToApp: "test-backend", ToPath: "/hello/*"},
} }
rewriteRules := []service.RewriteRule{ rewriteRules := []service.RewriteRule{
{Path: "^/old-api/(.*)$", ToPath: "/api/$1"}, {Path: "^/old-api/(.*)$", ToPath: "/api/$1"},
@ -130,6 +134,22 @@ func TestGateway(t *testing.T) {
t.Fatalf("Proxy regexp failed, got: %s", body) t.Fatalf("Proxy regexp failed, got: %s", body)
} }
// ============================================
// 测试 2.1: 极速通配符前缀匹配 (Discover)
// ============================================
req, _ = gohttp.NewRequest("GET", "http://127.0.0.1:"+gwPort+"/v2/world?x=2", nil)
req.Host = "gw.test"
res, err = client.Do(req)
body = ""
if err == nil && res != nil {
b, _ := io.ReadAll(res.Body)
res.Body.Close()
body = string(b)
}
if err != nil || !strings.Contains(body, "hello from backend, path: /hello/world?x=2") {
t.Fatalf("Proxy wildcard failed, got: %s", body)
}
// ============================================ // ============================================
// 测试 3: Rewrite 后再 Proxy // 测试 3: Rewrite 后再 Proxy
// ============================================ // ============================================

19
main.go
View File

@ -12,7 +12,24 @@ func main() {
_ = config.Load(&GatewayConf, "gateway") _ = config.Load(&GatewayConf, "gateway")
// 2. 初始化 Starter 信息 // 2. 初始化 Starter 信息
starter.SetAppInfo("gateway", "2.0.0") starter.SetAppInfo("gateway", "2.0.1")
starter.SetUsage(`High-performance, event-driven dynamic API gateway.
Configuration:
Uses env.yml or environment variables for base configuration.
Supports Nginx-like static routing via Proxy/Rewrite/Static declarations in yaml.
Supports real-time atomic hot-reloading via Redis Pub/Sub.
Routing Path Matching:
- Exact Match (Default): Path: "/api" matches EXACTLY "/api"
- Fast Prefix Match: Path: "/api/*" matches any path starting with "/api/"
- Regex Match: Path: "^/api/(.*)$" captures groups for replacement in ToPath
Host Matching (Fallback Order):
1. Exact Host+Port (e.g., "aa.com:8080")
2. Host Only (e.g., "aa.com")
3. Port Only (e.g., ":8080")
4. Global Wildcard (e.g., "*" or "")`)
// 3. 注册 Gateway 服务 // 3. 注册 Gateway 服务
// GatewayApp 自身实现了 starter.Service 和 starter.Reloader 接口 // GatewayApp 自身实现了 starter.Service 和 starter.Reloader 接口