From 83104e07f009001ee18771d1cfdece697e231447 Mon Sep 17 00:00:00 2001 From: haifzhu Date: Fri, 3 Jan 2025 22:44:49 +0800 Subject: [PATCH 1/2] feat: add nginx static-files wasm plugin --- .../wasm-go/extensions/static-files/README.md | 76 ++++++++++ .../wasm-go/extensions/static-files/VERSION | 1 + .../wasm-go/extensions/static-files/go.mod | 22 +++ .../wasm-go/extensions/static-files/go.sum | 28 ++++ .../wasm-go/extensions/static-files/main.go | 122 +++++++++++++++ .../wasm-go/extensions/static-files/utils.go | 46 ++++++ .../extensions/static-files/utils_test.go | 143 ++++++++++++++++++ .../conformance/tests/go-wasm-static-files.go | 60 ++++++++ .../tests/go-wasm-static-files.yaml | 51 +++++++ 9 files changed, 549 insertions(+) create mode 100644 plugins/wasm-go/extensions/static-files/README.md create mode 100644 plugins/wasm-go/extensions/static-files/VERSION create mode 100644 plugins/wasm-go/extensions/static-files/go.mod create mode 100644 plugins/wasm-go/extensions/static-files/go.sum create mode 100644 plugins/wasm-go/extensions/static-files/main.go create mode 100644 plugins/wasm-go/extensions/static-files/utils.go create mode 100644 plugins/wasm-go/extensions/static-files/utils_test.go create mode 100644 test/e2e/conformance/tests/go-wasm-static-files.go create mode 100644 test/e2e/conformance/tests/go-wasm-static-files.yaml diff --git a/plugins/wasm-go/extensions/static-files/README.md b/plugins/wasm-go/extensions/static-files/README.md new file mode 100644 index 0000000000..ef0708caac --- /dev/null +++ b/plugins/wasm-go/extensions/static-files/README.md @@ -0,0 +1,76 @@ +--- +title: static-files +keywords: [higress,static-files] +description: 静态文件转发功能 +--- + +# 功能说明 +`static-files`插件支持nginx静态文件的转发配置,static files插件配置支持指令: +- `root`: 定义root路径,转发请求为root path + request path +- `alias`: 定义alias路径,转发请求为alias path +- `index`: 默认首页文件 +- `try paths`: 请求基于不同的路径进行重试,直到请求到正确返回的请求 + +# 配置字段 + +| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 | +| -------- | -------- | -------- | -------- | -------- | +| `root` | string | 非必填 | - | root路径 | +| `alias_path` | string | 非必填 | - | alias待替换的路径 | +| `alias` | string | 非必填 | - | alias路径 | +| `index` | array of string | 非必填 | - | 首页文件列表 | +| `try_paths` | array of string | 必填 | - | 重试路径,比如`index.html`,`$uri`, `index.html` | +| `try_codes` | array of int | 非必填 | [403, 404] | 重试状态码,可自定义 | +| `timeout` | int | 非必填 | 1000 | 重试请求的超时时间,单位ms | + + +# 配置示例 + +## root + +```yaml +root: "/b" + +``` + +基于该配置开启插件,触发插件的请求curl "http://a.com/a", 会请求http:///b/a。 + +## alias + +```yaml +alias_path: "/a" +alias: "/b" + +``` + +基于该配置开启插件,触发插件的请求curl "http://a.com/a", 会请求http:///b。 + +## index + +```yaml +alias_path: "/a" +alias: "/b" +index_file: index.html + +``` + +基于该配置开启插件,触发插件的请求curl "http://a.com/a", 会依次请求 +- http:///b +- http:///b/index.html + + +## try_paths + +```yaml +try_paths: +- "$uri/" +- "$uri.html" +- "/index.html" + +``` + +基于该配置开启插件,触发插件的请求curl "http://a.com/a", 会依次请求 +- http:///a/ +- http:///a.html +- http:///index.html +如果请求返回码不是重试状态码,会直接返回该请求体,否则继续重试下一个请求,所有请求都不是重试状态码,会继续请求默认后端服务。 diff --git a/plugins/wasm-go/extensions/static-files/VERSION b/plugins/wasm-go/extensions/static-files/VERSION new file mode 100644 index 0000000000..afaf360d37 --- /dev/null +++ b/plugins/wasm-go/extensions/static-files/VERSION @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/plugins/wasm-go/extensions/static-files/go.mod b/plugins/wasm-go/extensions/static-files/go.mod new file mode 100644 index 0000000000..e72c67a40d --- /dev/null +++ b/plugins/wasm-go/extensions/static-files/go.mod @@ -0,0 +1,22 @@ +module static-files + +go 1.19 + +require ( + github.com/alibaba/higress/plugins/wasm-go v1.4.0 + github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc + github.com/stretchr/testify v1.8.4 + github.com/tidwall/gjson v1.17.1 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 // indirect + github.com/magefile/mage v1.14.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/resp v0.1.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/plugins/wasm-go/extensions/static-files/go.sum b/plugins/wasm-go/extensions/static-files/go.sum new file mode 100644 index 0000000000..fb99b08658 --- /dev/null +++ b/plugins/wasm-go/extensions/static-files/go.sum @@ -0,0 +1,28 @@ +github.com/alibaba/higress/plugins/wasm-go v1.4.0 h1:uFf+mbZ2iuRXJzRbmWBuxiHvNDMGf3PCBJ6TI86bopY= +github.com/alibaba/higress/plugins/wasm-go v1.4.0/go.mod h1:10jQXKsYFUF7djs+Oy7t82f4dbie9pISfP9FJwpPLuk= +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/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbGQ2DTIXHBHxWfqCYQW1fKjyJ/I7W1pMyUDeEA= +github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew= +github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc h1:t2AT8zb6N/59Y78lyRWedVoVWHNRSCBh0oWCC+bluTQ= +github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240327114451-d6b7174a84fc/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo= +github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo= +github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +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/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= +github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/resp v0.1.1 h1:Ly20wkhqKTmDUPlyM1S7pWo5kk0tDu8OoC/vFArXmwE= +github.com/tidwall/resp v0.1.1/go.mod h1:3/FrruOBAxPTPtundW0VXgmsQ4ZBA0Aw714lVYgwFa0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/plugins/wasm-go/extensions/static-files/main.go b/plugins/wasm-go/extensions/static-files/main.go new file mode 100644 index 0000000000..927f79a83e --- /dev/null +++ b/plugins/wasm-go/extensions/static-files/main.go @@ -0,0 +1,122 @@ +package main + +import ( + "net/http" + "strings" + + "github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper" + "github.com/higress-group/proxy-wasm-go-sdk/proxywasm" + "github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types" + "github.com/tidwall/gjson" +) + +// 默认超时时间为1s +var defaultTimeout uint32 = 1000 + +const VariableReplacedStr = "$uri" + +func main() { + wrapper.SetCtx( + "static-files", + wrapper.ParseConfigBy(parseConfig), + wrapper.ProcessRequestHeadersBy(onHttpRequestHeaders), + ) +} + +type StaticFilesConfig struct { + root string + alias string + aliasPath string + index []string + tryPaths []string + timeout uint32 + tryCodes []int + client wrapper.HttpClient +} + +func parseConfig(json gjson.Result, config *StaticFilesConfig, log wrapper.Log) error { + config.root = json.Get("root").String() + config.alias = json.Get("alias").String() + config.aliasPath = json.Get("alias_path").String() + for _, result := range json.Get("index").Array() { + config.index = append(config.index, result.String()) + } + + for _, result := range json.Get("try_paths").Array() { + config.tryPaths = append(config.tryPaths, result.String()) + } + + if json.Get("try_codes").String() == "" { + // tryCodes默认值为["404", "403"] + config.tryCodes = []int{http.StatusNotFound, http.StatusForbidden} + } else { + for _, result := range json.Get("try_codes").Array() { + config.tryCodes = append(config.tryCodes, int(result.Int())) + } + } + + timeout := json.Get("timeout").Int() + if timeout == 0 { + // tryPaths的timeout默认值为1s + config.timeout = defaultTimeout + } else { + config.timeout = uint32(timeout) + } + + config.client = wrapper.NewClusterClient(wrapper.RouteCluster{ + Host: json.Get("host").String(), + }) + return nil +} + +func tryHttpCall(tryPaths []string, config StaticFilesConfig, index int, path string, log wrapper.Log) { + if index >= len(tryPaths) { + proxywasm.ResumeHttpRequest() + return + } + + requestPath := strings.Replace(tryPaths[index], VariableReplacedStr, path, -1) + log.Debugf("try path request, path: %s", requestPath) + err := config.client.Get(requestPath, nil, + func(statusCode int, responseHeaders http.Header, responseBody []byte) { + if !contains(config.tryCodes, statusCode) { + proxywasm.SendHttpResponse(uint32(statusCode), convertHttpHeadersToStruct(responseHeaders), responseBody, -1) + return + } + tryHttpCall(tryPaths, config, index+1, path, log) + }, config.timeout) + + if err != nil { + log.Errorf("try path request failed, path %s, error: %s", requestPath, err.Error()) + tryHttpCall(tryPaths, config, index+1, path, log) + } +} + +func onHttpRequestHeaders(ctx wrapper.HttpContext, config StaticFilesConfig, log wrapper.Log) types.Action { + log.Debugf("static files request config: %+v", config) + path := ctx.Path() + tryPaths := make([]string, 0) + requestPath := path + if config.root != "" { + requestPath = getRootRequestPath(config.root, path) + tryPaths = append(tryPaths, requestPath) + } else if config.aliasPath != "" { + requestPath = getAliasRequestPath(config.alias, config.aliasPath, path) + tryPaths = append(tryPaths, requestPath) + } + + if len(config.index) != 0 { + tryPaths = append(tryPaths, *getIndexRequestPath(config.index, requestPath)...) + } + + if len(config.tryPaths) != 0 { + tryPaths = append(tryPaths, config.tryPaths...) + } + + if len(tryPaths) == 0 { + return types.ActionContinue + } + + tryHttpCall(tryPaths, config, 0, path, log) + return types.ActionPause +} diff --git a/plugins/wasm-go/extensions/static-files/utils.go b/plugins/wasm-go/extensions/static-files/utils.go new file mode 100644 index 0000000000..5526de5c38 --- /dev/null +++ b/plugins/wasm-go/extensions/static-files/utils.go @@ -0,0 +1,46 @@ +package main + +import ( + "net/http" + "strings" +) + +func convertHttpHeadersToStruct(responseHeaders http.Header) [][2]string { + headerStruct := make([][2]string, len(responseHeaders)) + i := 0 + for key, values := range responseHeaders { + headerStruct[i][0] = key + headerStruct[i][1] = values[0] + i++ + } + return headerStruct +} + +func getRootRequestPath(root string, path string) string { + return root + path +} + +func getAliasRequestPath(alias string, aliasPath string, path string) string { + return strings.Replace(path, aliasPath, alias, -1) +} + +func getIndexRequestPath(index []string, path string) *[]string { + paths := make([]string, 0) + for _, v := range index { + if strings.HasSuffix(path, "/") { + paths = append(paths, path+v) + } else { + paths = append(paths, path+"/"+v) + } + } + return &paths +} + +func contains(array []int, value int) bool { + for _, v := range array { + if v == value { + return true + } + } + return false +} diff --git a/plugins/wasm-go/extensions/static-files/utils_test.go b/plugins/wasm-go/extensions/static-files/utils_test.go new file mode 100644 index 0000000000..6a6543bbe0 --- /dev/null +++ b/plugins/wasm-go/extensions/static-files/utils_test.go @@ -0,0 +1,143 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestConvertHttpHeadersToStruct(t *testing.T) { + cases := []struct { + name string + httpHeaders map[string][]string + expected [][2]string + }{ + { + name: "empty header", + httpHeaders: map[string][]string{}, + expected: [][2]string{}, + }, + { + name: "headers with content type", + httpHeaders: map[string][]string{ + "Content-Type": []string{"application/json"}, + }, + expected: [][2]string{ + {"Content-Type", "application/json"}, + }, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + result := convertHttpHeadersToStruct(c.httpHeaders) + require.Equal(t, c.expected, result) + }) + } +} + +func TestGetRootRequestPath(t *testing.T) { + cases := []struct { + name string + root string + path string + expected string + }{ + { + name: "test1", + root: "/a", + path: "/index.html", + expected: "/a/index.html", + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + result := getRootRequestPath(c.root, c.path) + require.Equal(t, c.expected, result) + }) + } +} + +func TestGetAliasRequestPath(t *testing.T) { + cases := []struct { + name string + alias string + aliasPath string + path string + expected string + }{ + { + name: "test1", + alias: "/b", + aliasPath: "/a", + path: "/a/index.html", + expected: "/b/index.html", + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + result := getAliasRequestPath(c.alias, c.aliasPath, c.path) + require.Equal(t, c.expected, result) + }) + } +} + +func TestGetIndexRequestPath(t *testing.T) { + cases := []struct { + name string + index []string + path string + expected []string + }{ + { + name: "test1", + index: []string{"index.html", "index.php"}, + path: "/a", + expected: []string{"/a/index.html", "/a/index.php"}, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + result := *getIndexRequestPath(c.index, c.path) + require.Equal(t, c.expected, result) + }) + } +} + +func TestContains(t *testing.T) { + cases := []struct { + name string + array []int + value int + expected bool + }{ + { + name: "multi value, contains", + array: []int{404, 304}, + value: 404, + expected: true, + }, + { + name: "multi value, no contains", + array: []int{404, 304}, + value: 200, + expected: false, + }, + { + name: "one value contains", + array: []int{200}, + value: 200, + expected: true, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + result := contains(c.array, c.value) + require.Equal(t, c.expected, result) + }) + } +} diff --git a/test/e2e/conformance/tests/go-wasm-static-files.go b/test/e2e/conformance/tests/go-wasm-static-files.go new file mode 100644 index 0000000000..32f57c9536 --- /dev/null +++ b/test/e2e/conformance/tests/go-wasm-static-files.go @@ -0,0 +1,60 @@ +// Copyright (c) 2022 Alibaba Group Holding Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tests + +import ( + "testing" + + "github.com/alibaba/higress/test/e2e/conformance/utils/http" + "github.com/alibaba/higress/test/e2e/conformance/utils/suite" +) + +func init() { + Register(WasmPluginsStaticFiles) +} + +var WasmPluginsStaticFiles = suite.ConformanceTest{ + ShortName: "WasmPluginsStaticFiles", + Description: "The Ingress in the higress-conformance-infra namespace test the static files WASM plugin.", + Manifests: []string{"tests/go-wasm-static-files.yaml"}, + Features: []suite.SupportedFeature{suite.WASMGoConformanceFeature}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + testcases := []http.Assertion{ + { + Meta: http.AssertionMeta{ + TestCaseName: "Test Static Files Success", + TargetBackend: "infra-backend-v1", + TargetNamespace: "higress-conformance-infra", + }, + Request: http.AssertionRequest{ + ActualRequest: http.Request{ + Host: "foo.com", + Path: "/foo", + }, + }, + Response: http.AssertionResponse{ + ExpectedResponse: http.Response{ + StatusCode: 200, + }, + }, + }, + } + t.Run("WasmPlugins static files", func(t *testing.T) { + for _, testcase := range testcases { + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, suite.GatewayAddress, testcase) + } + }) + }, +} diff --git a/test/e2e/conformance/tests/go-wasm-static-files.yaml b/test/e2e/conformance/tests/go-wasm-static-files.yaml new file mode 100644 index 0000000000..cc3837c46f --- /dev/null +++ b/test/e2e/conformance/tests/go-wasm-static-files.yaml @@ -0,0 +1,51 @@ +# Copyright (c) 2022 Alibaba Group Holding Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + name: wasmplugin-static-files + namespace: higress-conformance-infra +spec: + ingressClassName: higress + rules: + - host: "foo.com" + http: + paths: + - pathType: Prefix + path: "/foo" + backend: + service: + name: infra-backend-v1 + port: + number: 8080 +--- +apiVersion: extensions.higress.io/v1alpha1 +kind: WasmPlugin +metadata: + name: static-files + namespace: higress-system +spec: + defaultConfigDisable: false + matchRules: + - config: + root: /foo + index: /index.html + try_paths: + - /path1 + configDisable: false + ingress: + - higress-conformance-infra/wasmplugin-static-files + url: oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/static-files:1.0.0 From ae6480c6270ba1f2794eacdef85384d1f7e82829 Mon Sep 17 00:00:00 2001 From: haifzhu Date: Sun, 5 Jan 2025 09:28:36 +0800 Subject: [PATCH 2/2] fix: optimize readme file --- .../wasm-go/extensions/static-files/README.md | 39 ++++++++----------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/plugins/wasm-go/extensions/static-files/README.md b/plugins/wasm-go/extensions/static-files/README.md index ef0708caac..c1dc20135e 100644 --- a/plugins/wasm-go/extensions/static-files/README.md +++ b/plugins/wasm-go/extensions/static-files/README.md @@ -1,15 +1,9 @@ ---- -title: static-files -keywords: [higress,static-files] -description: 静态文件转发功能 ---- - # 功能说明 `static-files`插件支持nginx静态文件的转发配置,static files插件配置支持指令: -- `root`: 定义root路径,转发请求为root path + request path -- `alias`: 定义alias路径,转发请求为alias path -- `index`: 默认首页文件 -- `try paths`: 请求基于不同的路径进行重试,直到请求到正确返回的请求 +- `root`: 定义root路径,转发请求为root path + request path。 +- `alias`: 定义alias路径,转发请求为alias path。 +- `index`: 默认首页文件列表,比如["index.html", "index.php"]等。 +- `try paths`: 请求基于不同的路径进行重试,直到请求到正确返回的请求。 # 配置字段 @@ -19,7 +13,7 @@ description: 静态文件转发功能 | `alias_path` | string | 非必填 | - | alias待替换的路径 | | `alias` | string | 非必填 | - | alias路径 | | `index` | array of string | 非必填 | - | 首页文件列表 | -| `try_paths` | array of string | 必填 | - | 重试路径,比如`index.html`,`$uri`, `index.html` | +| `try_paths` | array of string | 必填 | - | 转发路径列表,比如`index.html`,`$uri`, `index.html` | | `try_codes` | array of int | 非必填 | [403, 404] | 重试状态码,可自定义 | | `timeout` | int | 非必填 | 1000 | 重试请求的超时时间,单位ms | @@ -33,7 +27,7 @@ root: "/b" ``` -基于该配置开启插件,触发插件的请求curl "http://a.com/a", 会请求http:///b/a。 +基于该配置开启插件,触发插件的请求`http://a.com/a`, 请求会转发为`http://upstream/b/a`。 ## alias @@ -43,20 +37,21 @@ alias: "/b" ``` -基于该配置开启插件,触发插件的请求curl "http://a.com/a", 会请求http:///b。 +基于该配置开启插件,触发插件的请求`http://a.com/a`, 请求会转发为`http://upstream/b`。 ## index ```yaml alias_path: "/a" alias: "/b" -index_file: index.html +index: +- index.html ``` -基于该配置开启插件,触发插件的请求curl "http://a.com/a", 会依次请求 -- http:///b -- http:///b/index.html +基于该配置开启插件,触发插件的请求`http://a.com/a`, 请求会依次转发为: +- http://upstream/b +- http://upstream/b/index.html ## try_paths @@ -69,8 +64,8 @@ try_paths: ``` -基于该配置开启插件,触发插件的请求curl "http://a.com/a", 会依次请求 -- http:///a/ -- http:///a.html -- http:///index.html -如果请求返回码不是重试状态码,会直接返回该请求体,否则继续重试下一个请求,所有请求都不是重试状态码,会继续请求默认后端服务。 +基于该配置开启插件,触发插件的请求`http://a.com/a`, 请求会依次转发为: +- http://upstream/a/ +- http://upstream/a.html +- http://upstream/index.html +如果请求返回码不是重试状态码,会直接返回该请求体,否则继续转发下一个请求,所有请求都不是重试状态码,会继续转发到默认后端服务。