在为KrakenD实现插件时遇到无效节点类型的恐慌错误。

huangapple go评论101阅读模式
英文:

invalid node type panic when implementing a plugin for KrakenD

问题

我正在为无重定向插件开发一个插件。我正在使用krakend-ce 2.2.1(使用golang 1.19)。我遇到了以下恐慌错误:

gw_krakend_1  | [KRAKEND] 2023/03/15 - 21:09:06.675 ? DEBUG no_redirect_plugin: request received https://127.0.0.1:8443/ABC
gw_krakend_1  | [KRAKEND] 2023/03/15 - 21:09:06.689 ? DEBUG no_redirect_plugin: redirect detected https://127.0.0.1:8443/ABC
gw_krakend_1  | [KRAKEND] 2023/03/15 - 21:09:06.689 ? DEBUG Status code 302
gw_krakend_1  | 2023/03/15 21:09:06 http: panic serving [::1]:54778: invalid node type
gw_krakend_1  | goroutine 84 [running]:
gw_krakend_1  | net/http.(*conn).serve.func1()
gw_krakend_1  |         /usr/local/go/src/net/http/server.go:1854 +0xbf
gw_krakend_1  | panic({0x28cbb60, 0x34b5810})
gw_krakend_1  |         /usr/local/go/src/runtime/panic.go:890 +0x263
gw_krakend_1  | github.com/gin-gonic/gin.(*node).findCaseInsensitivePathRec(0x0?, {0xc0016ac2ec?, 0x0?}, {0xc0010fe800?, 0xc0016ac2ed?, 0xc000ced928?}, {0x0, 0x0, 0x0, 0x0}, ...)
gw_krakend_1  |         /go/pkg/mod/github.com/gin-gonic/gin@v1.8.2/tree.go:862 +0xa9d
gw_krakend_1  | github.com/gin-gonic/gin.(*node).findCaseInsensitivePath(0xc0016ac2ec?, {0xc0016ac2ec, 0x5}, 0x30?)
gw_krakend_1  |         /go/pkg/mod/github.com/gin-gonic/gin@v1.8.2/tree.go:669 +0x9c
gw_krakend_1  | github.com/gin-gonic/gin.redirectFixedPath(0xc000664300, 0xc0016ac2ec?, 0x60?)
gw_krakend_1  |         /go/pkg/mod/github.com/gin-gonic/gin@v1.8.2/gin.go:684 +0x5b
gw_krakend_1  | github.com/gin-gonic/gin.(*Engine).handleHTTPRequest(0xc000602b60, 0xc000664300)

看起来类似于这个问题:https://github.com/gin-gonic/gin/issues/2959,但是gin的版本已经在之前的krakend版本中升级过了。如果没有插件,它可以正常工作。我还修剪了最后的斜杠(由于某种原因,在某个地方添加了斜杠)。

另外,我使用与krakend相同的版本编译插件。

我的端点定义如下:

{
      "endpoint": "/",
      "input_headers":[
        "*"
      ],
      "input_query_strings":[
        "*"
      ],
      "method": "GET",
      "output_encoding": "no-op",
      "extra_config": {},
      "backend": [{
        "url_pattern": "",
        "encoding": "no-op",
        "sd": "static",
        "method": "GET",
        "extra_config": {
          "plugin/http-client": {
            "name": "no_redirect_plugin"
          }
        },
        "host": [
          "{{ env \"HOST\" }}"
        ],
        "disable_host_sanitize": false
    }]
},{
      "endpoint": "/{level1}",
      "input_headers":[
        "*"
      ],
      "input_query_strings":[
        "*"
      ],
      "method": "GET",
      "output_encoding": "no-op",
      "extra_config": {
      },
      "backend": [{
        "url_pattern": "/{level1}",
        "encoding": "no-op",
        "sd": "static",
        "method": "GET",
        "extra_config": {
          "plugin/http-client": {
            "name": "no_redirect_plugin"
          }
        },
        "host": [
          "{{ env \"HOST\" }}"
        ],
        "disable_host_sanitize": false
    }]
},{
      "endpoint": "/{level1}/{level2}",
      "input_headers":[
        "*"
      ],
      "input_query_strings":[
        "*"
      ],
      "method": "GET",
      "output_encoding": "no-op",
      "extra_config": {
      },
      "backend": [{
        "url_pattern": "/{level1}/{level2}",
        "encoding": "no-op",
        "sd": "static",
        "method": "GET",
        "extra_config": {
          "plugin/http-client": {
            "name": "no_redirect_plugin"
          }
        },
        "host": [
          "{{ env \"HOST\" }}"
        ],
        "disable_host_sanitize": false
    }]
}

编辑:我的浏览器仍然显示/ABC/而不是/ABC,这可能会导致路由冲突(例如:https://github.com/krakendio/krakend-ce/issues/386)。无论如何,我不知道斜杠是在哪里添加的(我以为我已经修剪好了...看起来我没有)。

编辑2:我找到了这个链接https://www.krakend.io/docs/service-settings/router-options/,通过设置"disable_redirect_fixed_path": true和"disable_redirect_trailing_slash": true,不再出现恐慌错误...现在我遇到了另一个问题:当我的单体应用程序尝试重定向到/a/或任何以斜杠结尾的路由时,会出现无限重定向(开个玩笑,只有10次)。在没有插件的情况下,KrakenD过去会自己处理重定向...

我猜主要问题在于路由冲突,当/{level1}和/{level1}/{level2}同时与/ABC/匹配时。

有什么想法吗?

英文:

im working on a plugin for no redirects. Im using krakend-ce 2.2.1 (with golang 1.19) im getting this panic:

gw_krakend_1  | [KRAKEND] 2023/03/15 - 21:09:06.675 ? DEBUG no_redirect_plugin: request received https://127.0.0.1:8443/ABC
gw_krakend_1  | [KRAKEND] 2023/03/15 - 21:09:06.689 ? DEBUG no_redirect_plugin: redirect detected https://127.0.0.1:8443/ABC
gw_krakend_1  | [KRAKEND] 2023/03/15 - 21:09:06.689 ? DEBUG Status code 302
gw_krakend_1  | 2023/03/15 21:09:06 http: panic serving [::1]:54778: invalid node type
gw_krakend_1  | goroutine 84 [running]:
gw_krakend_1  | net/http.(*conn).serve.func1()
gw_krakend_1  |         /usr/local/go/src/net/http/server.go:1854 +0xbf
gw_krakend_1  | panic({0x28cbb60, 0x34b5810})
gw_krakend_1  |         /usr/local/go/src/runtime/panic.go:890 +0x263
gw_krakend_1  | github.com/gin-gonic/gin.(*node).findCaseInsensitivePathRec(0x0?, {0xc0016ac2ec?, 0x0?}, {0xc0010fe800?, 0xc0016ac2ed?, 0xc000ced928?}, {0x0, 0x0, 0x0, 0x0}, ...)
gw_krakend_1  |         /go/pkg/mod/github.com/gin-gonic/gin@v1.8.2/tree.go:862 +0xa9d
gw_krakend_1  | github.com/gin-gonic/gin.(*node).findCaseInsensitivePath(0xc0016ac2ec?, {0xc0016ac2ec, 0x5}, 0x30?)
gw_krakend_1  |         /go/pkg/mod/github.com/gin-gonic/gin@v1.8.2/tree.go:669 +0x9c
gw_krakend_1  | github.com/gin-gonic/gin.redirectFixedPath(0xc000664300, 0xc0016ac2ec?, 0x60?)
gw_krakend_1  |         /go/pkg/mod/github.com/gin-gonic/gin@v1.8.2/gin.go:684 +0x5b
gw_krakend_1  | github.com/gin-gonic/gin.(*Engine).handleHTTPRequest(0xc000602b60, 0xc000664300)

seems similar to it https://github.com/gin-gonic/gin/issues/2959 but the version of gin was already upgraded on previous versions of krakend. It would be weird if they were really capital letters, without the plugin it works perfect. Im also triming the last / (for some reason its added in some point)

btw, im compiling the plugin with the same version of krakend.

package main

import (
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
)

func main() {}

var ClientRegisterer = registerer("no_redirect_plugin")

type registerer string

type Logger interface {
	Debug(v ...interface{})
	Info(v ...interface{})
	Warning(v ...interface{})
	Error(v ...interface{})
	Critical(v ...interface{})
	Fatal(v ...interface{})
}

var logger Logger = nil

func (registerer) RegisterLogger(v interface{}) {
	l, ok := v.(Logger)
	if !ok {
		return
	}
	logger = l
	logger.Info(fmt.Sprintf("[PLUGIN: %s] Logger loaded", ClientRegisterer))
}

func (r registerer) RegisterClients(f func(
	name string,
	handler func(context.Context, map[string]interface{}) (http.Handler, error),
)) {
	f(string(r), r.registerClients)
}

func (r registerer) registerClients(_ context.Context, extra map[string]interface{}) (http.Handler, error) {
	name, ok := extra["name"].(string)
	if !ok {
		return nil, errors.New("wrong config")
	}

	if name != string(r) {
		return nil, fmt.Errorf("unknown register %s", name)
	}

	httpClient := &http.Client{
		CheckRedirect: func(req *http.Request, via []*http.Request) error {

			// Trim the last "/" character from the URL if it exists
			urlStr := strings.TrimRight(req.URL.String(), "/")
			req.URL, _ = url.Parse(urlStr)

			logger.Debug("no_redirect_plugin: redirect detected", req.URL.String())
			return http.ErrUseLastResponse
		},
	}

	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {

		// Trim the last "/" character from the URL if it exists
		urlStr := strings.TrimRight(req.URL.String(), "/")
		req.URL, _ = url.Parse(urlStr)

		logger.Debug("no_redirect_plugin: request received", req.URL.String())
		resp, err := httpClient.Do(req)
		if err != nil {
			logger.Debug("Error while proxying request", err.Error())
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		defer resp.Body.Close()

		for k, hs := range resp.Header {
			for _, h := range hs {
				w.Header().Add(k, h)
			}
		}

		w.WriteHeader(resp.StatusCode)
		logger.Debug("Status code", resp.StatusCode)
		if resp.Body == nil {
			return
		}

		_, err = io.Copy(w, resp.Body)
		if err != nil {
			logger.Debug("Error while proxying request 2", err.Error())
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

	}), nil
}

My endpoints are defined like this:

{
     "endpoint": "/",
     "input_headers":[
       "*"
     ],
     "input_query_strings":[
       "*"
     ],
     "method": "GET",
     "output_encoding": "no-op",
     "extra_config": {},
     "backend": [{
       "url_pattern": "",
       "encoding": "no-op",
       "sd": "static",
       "method": "GET",
       "extra_config": {
         "plugin/http-client": {
           "name": "no_redirect_plugin"
         }
       },
       "host": [
         "{{ env "HOST" }}"
       ],
       "disable_host_sanitize": false
   }]
},{
     "endpoint": "/{level1}",
     "input_headers":[
       "*"
     ],
     "input_query_strings":[
       "*"
     ],
     "method": "GET",
     "output_encoding": "no-op",
     "extra_config": {
     },
     "backend": [{
       "url_pattern": "/{level1}",
       "encoding": "no-op",
       "sd": "static",
       "method": "GET",
       "extra_config": {
         "plugin/http-client": {
           "name": "no_redirect_plugin"
         }
       },
       "host": [
         "{{ env "HOST" }}"
       ],
       "disable_host_sanitize": false
   }]
},{
     "endpoint": "/{level1}/{level2}",
     "input_headers":[
       "*"
     ],
     "input_query_strings":[
       "*"
     ],
     "method": "GET",
     "output_encoding": "no-op",
     "extra_config": {
     },
     "backend": [{
       "url_pattern": "/{level1}/{level2}",
       "encoding": "no-op",
       "sd": "static",
       "method": "GET",
       "extra_config": {
         "plugin/http-client": {
           "name": "no_redirect_plugin"
         }
       },
       "host": [
         "{{ env "HOST" }}"
       ],
       "disable_host_sanitize": false
   }]
}

EDIT: My browser is still showing /ABC/ instead of /ABC which may generate a posible colide between routes (like here: https://github.com/krakendio/krakend-ce/issues/386) anyways i dont know where the slash is being added (i thought i trimmed it for good... seems i didnt)

EDIT2: I found this https://www.krakend.io/docs/service-settings/router-options/ and with "disable_redirect_fixed_path": true
and "disable_redirect_trailing_slash": true, it dont panic anymore... now i have another problem: infinite redirects (joking just 10) when my monolith tries to redirect to /a/ or any route with slash at the end, this worked before the plugin because KrakenD used to handle the redirects by its own...

i guess the principal issue here is the routing colide, when /{level1} and /{level1}/{level2} matches at the same time with /ABC/

Ideas?

答案1

得分: 0

好的,我会为你翻译以下内容:

很好,为了解决这个问题,我尝试使用这个配置https://www.krakend.io/docs/enterprise/endpoints/wildcard/创建了一个通配符+无重定向插件,但是即使使用了copilot和gpt4,我还是失败了,我敢你来实现这个。所以我用另一种方法解决了这个问题:我将网关放在我的单体应用程序前面,每当请求失败时,我添加了路由...因为我们没有记录的路由(*哭)。对于需要无重定向插件的文件,它完美地工作了。这是一个糟糕的解决方案,但它至今为止还有效,并且没有花费我想象中的那么长时间。

英文:

Good, for solving this i tried to create a wildcard+no_redirect plugin with this https://www.krakend.io/docs/enterprise/endpoints/wildcard/ configuration but i failed even with copilot&gpt4, i dare you to implement this. So i solved it with another aproach: i put the gateway in front of my monolith and everytime the request failed i added the route... because we have no documented routes (*cries). For the files that needs the no redirect plugin it worked perfectly. An aweful solution but it worked till now, and it didn't take as long as I thought

huangapple
  • 本文由 发表于 2023年3月16日 21:25:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/75756901.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定