Skip to content

Commit d2b134f

Browse files
丹坤heimanba
丹坤
authored andcommitted
feat: 🎸 添加 skipedRoutes以及skipedByHeaders 配置,忽略某些路由进入灰度插件处理
1 parent 32e5a59 commit d2b134f

File tree

6 files changed

+75
-29
lines changed

6 files changed

+75
-29
lines changed

plugins/wasm-go/extensions/frontend-gray/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ description: 前端灰度插件配置参考
2020
| `localStorageGrayKey` | string | 非必填 | - | 使用JWT鉴权方式,用户ID的唯一标识来自`localStorage`中,如果配置了当前参数,则`grayKey`失效 |
2121
| `graySubKey` | string | 非必填 | - | 用户身份信息可能以JSON形式透出,比如:`userInfo:{ userCode:"001" }`,当前例子`graySubKey`取值为`userCode` |
2222
| `userStickyMaxAge` | int | 非必填 | 172800 | 用户粘滞的时长:单位为秒,默认为`172800`,2天时间 |
23+
| `skippedPathPrefixes` | array of strings | 非必填 | - | 用于排除特定路径,避免当前插件处理这些请求。例如,在 rewrite 场景下,XHR 接口请求 `/api/xxx` 如果经过插件转发逻辑,可能会导致非预期的结果。 |
24+
| `skippedByHeaders` | array of string | 非必填 | - | 用于通过请求头过滤,指定哪些请求不被当前插件处理。`skippedPathPrefixes` 的优先级高于当前插件的配置。 |
2325
| `rules` | array of object | 必填 | - | 用户定义不同的灰度规则,适配不同的灰度场景 |
2426
| `rewrite` | object | 必填 | - | 重写配置,一般用于OSS/CDN前端部署的重写配置 |
2527
| `baseDeployment` | object | 非必填 | - | 配置Base基线规则的配置 |

plugins/wasm-go/extensions/frontend-gray/config/config.go

+5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const (
1212
XPreHigressTag = "x-pre-higress-tag"
1313
IsPageRequest = "is-page-request"
1414
IsNotFound = "is-not-found"
15+
EnabledGray = "enabled-gray"
1516
)
1617

1718
type LogInfo func(format string, args ...interface{})
@@ -61,6 +62,8 @@ type GrayConfig struct {
6162
GrayDeployments []*Deployment
6263
BackendGrayTag string
6364
Injection *Injection
65+
SkippedPathPrefixes []string
66+
SkippedByHeaders []string
6467
}
6568

6669
func convertToStringList(results []gjson.Result) []string {
@@ -91,6 +94,8 @@ func JsonToGrayConfig(json gjson.Result, grayConfig *GrayConfig) {
9194
grayConfig.BackendGrayTag = json.Get("backendGrayTag").String()
9295
grayConfig.UserStickyMaxAge = json.Get("userStickyMaxAge").String()
9396
grayConfig.Html = json.Get("html").String()
97+
grayConfig.SkippedPathPrefixes = convertToStringList(json.Get("skippedPathPrefixes").Array())
98+
grayConfig.SkippedByHeaders = convertToStringList(json.Get("skippedByHeaders").Array())
9499

95100
if grayConfig.UserStickyMaxAge == "" {
96101
// 默认值2天

plugins/wasm-go/extensions/frontend-gray/envoy.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ static_resources:
8282
"/app1": "/mfe/app1/{version}"
8383
}
8484
},
85+
"skippedPathPrefixes": [
86+
"/api/"
87+
],
8588
"baseDeployment": {
8689
"version": "dev"
8790
},

plugins/wasm-go/extensions/frontend-gray/main.go

+19-13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"fmt"
55
"net/http"
6+
"path"
67
"strings"
78

89
"github.com/alibaba/higress/plugins/wasm-go/extensions/frontend-gray/config"
@@ -32,15 +33,18 @@ func parseConfig(json gjson.Result, grayConfig *config.GrayConfig, log wrapper.L
3233
}
3334

3435
func onHttpRequestHeaders(ctx wrapper.HttpContext, grayConfig config.GrayConfig, log wrapper.Log) types.Action {
35-
if !util.IsGrayEnabled(grayConfig) {
36+
requestPath, _ := proxywasm.GetHttpRequestHeader(":path")
37+
requestPath = path.Clean(requestPath)
38+
enabledGray := util.IsGrayEnabled(grayConfig, requestPath)
39+
ctx.SetContext(config.EnabledGray, enabledGray)
40+
41+
if !enabledGray {
42+
ctx.DontReadRequestBody()
3643
return types.ActionContinue
3744
}
3845

3946
cookies, _ := proxywasm.GetHttpRequestHeader("cookie")
40-
path, _ := proxywasm.GetHttpRequestHeader(":path")
41-
fetchMode, _ := proxywasm.GetHttpRequestHeader("sec-fetch-mode")
42-
43-
isPageRequest := util.IsPageRequest(fetchMode, path)
47+
isPageRequest := util.IsPageRequest(requestPath)
4448
hasRewrite := len(grayConfig.Rewrite.File) > 0 || len(grayConfig.Rewrite.Index) > 0
4549
grayKeyValueByCookie := util.ExtractCookieValueByKey(cookies, grayConfig.GrayKey)
4650
grayKeyValueByHeader, _ := proxywasm.GetHttpRequestHeader(grayConfig.GrayKey)
@@ -73,7 +77,7 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, grayConfig config.GrayConfig,
7377
} else {
7478
deployment = util.FilterGrayRule(&grayConfig, grayKeyValue)
7579
}
76-
log.Infof("index deployment: %v, path: %v, backend: %v, xPreHigressVersion: %s,%s", deployment, path, deployment.BackendVersion, preVersion, preUniqueClientId)
80+
log.Infof("index deployment: %v, path: %v, backend: %v, xPreHigressVersion: %s,%s", deployment, requestPath, deployment.BackendVersion, preVersion, preUniqueClientId)
7781
} else {
7882
grayDeployment := util.FilterGrayRule(&grayConfig, grayKeyValue)
7983
deployment = util.GetVersion(grayConfig, grayDeployment, preVersion, isPageRequest)
@@ -91,22 +95,23 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, grayConfig config.GrayConfig,
9195
}
9296

9397
if hasRewrite {
94-
rewritePath := path
98+
rewritePath := requestPath
9599
if isPageRequest {
96-
rewritePath = util.IndexRewrite(path, deployment.Version, grayConfig.Rewrite.Index)
100+
rewritePath = util.IndexRewrite(requestPath, deployment.Version, grayConfig.Rewrite.Index)
97101
} else {
98-
rewritePath = util.PrefixFileRewrite(path, deployment.Version, grayConfig.Rewrite.File)
102+
rewritePath = util.PrefixFileRewrite(requestPath, deployment.Version, grayConfig.Rewrite.File)
99103
}
100-
if path != rewritePath {
101-
log.Infof("rewrite path:%s, rewritePath:%s, Version:%v", path, rewritePath, deployment.Version)
104+
if requestPath != rewritePath {
105+
log.Infof("rewrite path:%s, rewritePath:%s, Version:%v", requestPath, rewritePath, deployment.Version)
102106
proxywasm.ReplaceHttpRequestHeader(":path", rewritePath)
103107
}
104108
}
105109
return types.ActionContinue
106110
}
107111

108112
func onHttpResponseHeader(ctx wrapper.HttpContext, grayConfig config.GrayConfig, log wrapper.Log) types.Action {
109-
if !util.IsGrayEnabled(grayConfig) {
113+
enabledGray, _ := ctx.GetContext(config.EnabledGray).(bool)
114+
if !enabledGray {
110115
ctx.DontReadResponseBody()
111116
return types.ActionContinue
112117
}
@@ -179,7 +184,8 @@ func onHttpResponseHeader(ctx wrapper.HttpContext, grayConfig config.GrayConfig,
179184
}
180185

181186
func onHttpResponseBody(ctx wrapper.HttpContext, grayConfig config.GrayConfig, body []byte, log wrapper.Log) types.Action {
182-
if !util.IsGrayEnabled(grayConfig) {
187+
enabledGray, _ := ctx.GetContext(config.EnabledGray).(bool)
188+
if !enabledGray {
183189
return types.ActionContinue
184190
}
185191
isPageRequest, ok := ctx.GetContext(config.IsPageRequest).(bool)

plugins/wasm-go/extensions/frontend-gray/util/utils.go

+37-5
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,39 @@ func GetRealIpFromXff(xff string) string {
4747
return ""
4848
}
4949

50-
func IsGrayEnabled(grayConfig config.GrayConfig) bool {
50+
func IsRequestSkippedByHeaders(grayConfig config.GrayConfig) bool {
51+
secFetchMode, _ := proxywasm.GetHttpRequestHeader("sec-fetch-mode")
52+
upgrade, _ := proxywasm.GetHttpRequestHeader("upgrade")
53+
if len(grayConfig.SkippedByHeaders) == 0 {
54+
// 默认不走插件逻辑的header
55+
return secFetchMode == "cors" || upgrade == "websocket"
56+
}
57+
for _, configHeader := range grayConfig.SkippedByHeaders {
58+
header, _ := proxywasm.GetHttpRequestHeader(configHeader)
59+
if header != "" {
60+
return true
61+
}
62+
}
63+
return false
64+
}
65+
66+
func IsGrayEnabled(grayConfig config.GrayConfig, requestPath string) bool {
67+
// 当前路径中前缀为 SkipedRoute,则不走插件逻辑
68+
for _, prefix := range grayConfig.SkippedPathPrefixes {
69+
if strings.HasPrefix(requestPath, prefix) {
70+
return false
71+
}
72+
}
73+
74+
// 如果是首页,进入插件逻辑
75+
if IsPageRequest(requestPath) {
76+
return true
77+
}
78+
// 检查header标识,判断是否需要跳过
79+
if IsRequestSkippedByHeaders(grayConfig) {
80+
return false
81+
}
82+
5183
// 检查是否存在重写主机
5284
if grayConfig.Rewrite != nil && grayConfig.Rewrite.Host != "" {
5385
return true
@@ -132,11 +164,11 @@ var indexSuffixes = []string{
132164
".html", ".htm", ".jsp", ".php", ".asp", ".aspx", ".erb", ".ejs", ".twig",
133165
}
134166

135-
func IsPageRequest(fetchMode string, myPath string) bool {
136-
if fetchMode == "cors" {
137-
return false
167+
func IsPageRequest(requestPath string) bool {
168+
if requestPath == "/" || requestPath == "" {
169+
return true
138170
}
139-
ext := path.Ext(myPath)
171+
ext := path.Ext(requestPath)
140172
return ext == "" || ContainsValue(indexSuffixes, ext)
141173
}
142174

plugins/wasm-go/extensions/frontend-gray/util/utils_test.go

+9-11
Original file line numberDiff line numberDiff line change
@@ -108,22 +108,20 @@ func TestPrefixFileRewrite(t *testing.T) {
108108

109109
func TestIsPageRequest(t *testing.T) {
110110
var tests = []struct {
111-
fetchMode string
112-
p string
113-
output bool
111+
p string
112+
output bool
114113
}{
115-
{"cors", "/js/a.js", false},
116-
{"no-cors", "/js/a.js", false},
117-
{"no-cors", "/images/a.png", false},
118-
{"no-cors", "/index", true},
119-
{"cors", "/inde", false},
120-
{"no-cors", "/index.html", true},
121-
{"no-cors", "/demo.php", true},
114+
{"/js/a.js", false},
115+
{"/js/a.js", false},
116+
{"/images/a.png", false},
117+
{"/index", true},
118+
{"/index.html", true},
119+
{"/demo.php", true},
122120
}
123121
for _, test := range tests {
124122
testPath := test.p
125123
t.Run(testPath, func(t *testing.T) {
126-
output := IsPageRequest(test.fetchMode, testPath)
124+
output := IsPageRequest(testPath)
127125
assert.Equal(t, test.output, output)
128126
})
129127
}

0 commit comments

Comments
 (0)