From ea99159d51639f5b7d3e996a44a77d03b42c97dc Mon Sep 17 00:00:00 2001 From: Hazel0928 <55099364+Hazel0928@users.noreply.github.com> Date: Thu, 26 Sep 2024 22:38:33 +0800 Subject: [PATCH] feat: support frontend-gray plugin's envoy.yaml file to host HTML (#1343) Co-authored-by: Kent Dong --- .../extensions/frontend-gray/config/config.go | 2 + .../extensions/frontend-gray/envoy.yaml | 4 +- .../wasm-go/extensions/frontend-gray/main.go | 44 ++++++++++--------- .../extensions/frontend-gray/util/utils.go | 25 +++++++++++ .../frontend-gray/util/utils_test.go | 19 ++++++++ 5 files changed, 72 insertions(+), 22 deletions(-) diff --git a/plugins/wasm-go/extensions/frontend-gray/config/config.go b/plugins/wasm-go/extensions/frontend-gray/config/config.go index fd1c26b15..de689aad2 100644 --- a/plugins/wasm-go/extensions/frontend-gray/config/config.go +++ b/plugins/wasm-go/extensions/frontend-gray/config/config.go @@ -55,6 +55,7 @@ type GrayConfig struct { GraySubKey string Rules []*GrayRule Rewrite *Rewrite + Html string BaseDeployment *Deployment GrayDeployments []*Deployment BackendGrayTag string @@ -84,6 +85,7 @@ func JsonToGrayConfig(json gjson.Result, grayConfig *GrayConfig) { grayConfig.GraySubKey = json.Get("graySubKey").String() grayConfig.BackendGrayTag = json.Get("backendGrayTag").String() grayConfig.UserStickyMaxAge = json.Get("userStickyMaxAge").String() + grayConfig.Html = json.Get("html").String() if grayConfig.UserStickyMaxAge == "" { // 默认值2天 diff --git a/plugins/wasm-go/extensions/frontend-gray/envoy.yaml b/plugins/wasm-go/extensions/frontend-gray/envoy.yaml index e859c29a5..6dabed21d 100644 --- a/plugins/wasm-go/extensions/frontend-gray/envoy.yaml +++ b/plugins/wasm-go/extensions/frontend-gray/envoy.yaml @@ -107,7 +107,8 @@ static_resources: "" ] } - } + }, + "html": "\n \n\napp1\n\n\n\n\t测试替换html版本\n\t
\n\t版本: {version}\n\t
\n\t\n\n" } - name: envoy.filters.http.router typed_config: @@ -116,7 +117,6 @@ static_resources: - name: httpbin connect_timeout: 30s type: LOGICAL_DNS - # Comment out the following line to test on v6 networks dns_lookup_family: V4_ONLY lb_policy: ROUND_ROBIN load_assignment: diff --git a/plugins/wasm-go/extensions/frontend-gray/main.go b/plugins/wasm-go/extensions/frontend-gray/main.go index 148751cc3..a6207e792 100644 --- a/plugins/wasm-go/extensions/frontend-gray/main.go +++ b/plugins/wasm-go/extensions/frontend-gray/main.go @@ -184,12 +184,33 @@ func onHttpResponseBody(ctx wrapper.HttpContext, grayConfig config.GrayConfig, b isPageRequest = false // 默认值 } frontendVersion := ctx.GetContext(config.XPreHigressTag).(string) - isNotFound, ok := ctx.GetContext(config.IsNotFound).(bool) if !ok { isNotFound = false // 默认值 } + // 检查是否存在自定义 HTML, 如有则省略 rewrite.indexRouting 的内容 + if grayConfig.Html != "" { + log.Debugf("Returning custom HTML from config.") + // 替换响应体为 config.Html 内容 + if err := proxywasm.ReplaceHttpResponseBody([]byte(grayConfig.Html)); err != nil { + log.Errorf("Error replacing response body: %v", err) + return types.ActionContinue + } + + newHtml := util.InjectContent(grayConfig.Html, grayConfig.Injection) + // 替换当前html加载的动态文件版本 + newHtml = strings.ReplaceAll(newHtml, "{version}", frontendVersion) + + // 最终替换响应体 + if err := proxywasm.ReplaceHttpResponseBody([]byte(newHtml)); err != nil { + log.Errorf("Error replacing injected response body: %v", err) + return types.ActionContinue + } + + return types.ActionContinue + } + if isPageRequest && isNotFound && grayConfig.Rewrite.Host != "" && grayConfig.Rewrite.NotFound != "" { client := wrapper.NewClusterClient(wrapper.RouteCluster{Host: grayConfig.Rewrite.Host}) @@ -204,30 +225,13 @@ func onHttpResponseBody(ctx wrapper.HttpContext, grayConfig config.GrayConfig, b // 将原始字节转换为字符串 newBody := string(body) - // 收集需要插入的内容 - headInjection := strings.Join(grayConfig.Injection.Head, "\n") - bodyFirstInjection := strings.Join(grayConfig.Injection.Body.First, "\n") - bodyLastInjection := strings.Join(grayConfig.Injection.Body.Last, "\n") - - // 使用 strings.Builder 来提高性能 - var sb strings.Builder - // 预分配内存,避免多次内存分配 - sb.Grow(len(newBody) + len(headInjection) + len(bodyFirstInjection) + len(bodyLastInjection)) - sb.WriteString(newBody) - - // 进行替换 - content := sb.String() - content = strings.ReplaceAll(content, "", fmt.Sprintf("%s\n", headInjection)) - content = strings.ReplaceAll(content, "", fmt.Sprintf("\n%s", bodyFirstInjection)) - content = strings.ReplaceAll(content, "", fmt.Sprintf("%s\n", bodyLastInjection)) - - // 最终结果 - newBody = content + newBody = util.InjectContent(newBody, grayConfig.Injection) if err := proxywasm.ReplaceHttpResponseBody([]byte(newBody)); err != nil { return types.ActionContinue } } + return types.ActionContinue } diff --git a/plugins/wasm-go/extensions/frontend-gray/util/utils.go b/plugins/wasm-go/extensions/frontend-gray/util/utils.go index a8c096816..ab7b2d475 100644 --- a/plugins/wasm-go/extensions/frontend-gray/util/utils.go +++ b/plugins/wasm-go/extensions/frontend-gray/util/utils.go @@ -278,3 +278,28 @@ func FilterGrayWeight(grayConfig *config.GrayConfig, preVersion string, preUniqu } return nil } + +// InjectContent 用于将内容注入到 HTML 文档的指定位置 +func InjectContent(originalHtml string, injectionConfig *config.Injection) string { + + headInjection := strings.Join(injectionConfig.Head, "\n") + bodyFirstInjection := strings.Join(injectionConfig.Body.First, "\n") + bodyLastInjection := strings.Join(injectionConfig.Body.Last, "\n") + + // 使用 strings.Builder 来提高性能 + var sb strings.Builder + // 预分配内存,避免多次内存分配 + sb.Grow(len(originalHtml) + len(headInjection) + len(bodyFirstInjection) + len(bodyLastInjection)) + sb.WriteString(originalHtml) + + modifiedHtml := sb.String() + + // 注入到头部 + modifiedHtml = strings.ReplaceAll(modifiedHtml, "", headInjection + "\n") + // 注入到body头 + modifiedHtml = strings.ReplaceAll(modifiedHtml, "", "\n" + bodyFirstInjection) + // 注入到body尾 + modifiedHtml = strings.ReplaceAll(modifiedHtml, "", bodyLastInjection + "\n") + + return modifiedHtml +} diff --git a/plugins/wasm-go/extensions/frontend-gray/util/utils_test.go b/plugins/wasm-go/extensions/frontend-gray/util/utils_test.go index 7ba014225..d51e17f32 100644 --- a/plugins/wasm-go/extensions/frontend-gray/util/utils_test.go +++ b/plugins/wasm-go/extensions/frontend-gray/util/utils_test.go @@ -122,3 +122,22 @@ func TestFilterGrayWeight(t *testing.T) { }) } } + +func TestReplaceHtml(t *testing.T) { + var tests = []struct { + name string + input string + }{ + {"demo", `{"injection":{"head":[""],"body":{"first":[""],"last":[""]},"last":[""]},"html": "\n \n\napp1\n\n\n\n\t测试替换html版本\n\t
\n\t版本: {version}\n\t
\n\t\n\n"}`}, + {"demo-noBody", `{"injection":{"head":[""],"body":{"first":[""],"last":[""]},"last":[""]},"html": "\n \n\napp1\n\n\n"}`}, + } + for _, test := range tests { + testName := test.name + t.Run(testName, func(t *testing.T) { + grayConfig := &config.GrayConfig{} + config.JsonToGrayConfig(gjson.Parse(test.input), grayConfig) + result := InjectContent(grayConfig.Html, grayConfig.Injection) + t.Logf("result-----: %v", result) + }) + } +}