apache / apisix-go-plugin-runner

Go Plugin Runner for APISIX
https://apisix.apache.org/
Apache License 2.0
169 stars 69 forks source link

request help: support http proxy #53

Closed GhangZh closed 2 years ago

GhangZh commented 2 years ago

Issue description

I want to support the forward-auth , but how does go-pugin-runner support me to proxy the current request directly to the url, and then process the response and pass it on? I wrote a version in lua, but our technology stack is unified with go, so I want to use go to implement

    local core = require("apisix.core")
    local http = require("resty.http")
    local http_new = http.new()
    local res, err = http_new:request_uri("https://forward-auth.xxx.com", {
        ssl_verify = false,
        method = "GET",
        headers = {
            ["X-Forwarded-User"] = core.request.header(ctx, "X-Forwarded-User"),
            ["X-Forwarded-UID"] = core.request.header(ctx, "X-Forwarded-UID"),
            ["Cookie"]=core.request.header(ctx,"Cookie")
        },
    })
    if err ~= nil then
        core.log.error("==== Serverless Request Error: ", err)
        return
    end
    if (res ~= nil) then
        for k, v in pairs(res.headers) do
            core.response.set_header(k, v)
        end
    end
    if res.status == 302 then
        core.response.set_header("Location", res.headers.location)
        core.response.exit(302)
        return
    end

Environment

spacewander commented 2 years ago
  1. you can get/set the header via Request.Header, see https://pkg.go.dev/github.com/apache/apisix-go-plugin-runner@v0.2.0/pkg/http#Header
  2. you can stop the request with headers, see https://github.com/apache/apisix-go-plugin-runner/blob/195bd64e4d0edeb471a43016f0c3f0dad59f86b9/cmd/go-runner/plugins/say.go#L61
  3. currently, there is no way to set response header without stopping the request (the core.response.set_header(k, v) in your example). Maybe you can open an issue to track it?
GhangZh commented 2 years ago
  1. you can get/set the header via Request.Header, see https://pkg.go.dev/github.com/apache/apisix-go-plugin-runner@v0.2.0/pkg/http#Header
  2. you can stop the request with headers, see https://github.com/apache/apisix-go-plugin-runner/blob/195bd64e4d0edeb471a43016f0c3f0dad59f86b9/cmd/go-runner/plugins/say.go#L61
  3. currently, there is no way to set response header without stopping the request (the core.response.set_header(k, v) in your example). Maybe you can open an issue to track it?

I want to proxy all the responses. Is there any way to do that?

GhangZh commented 2 years ago

I wrote a demo, but I found that the response body is empty ,For example, if I add this plugin to luacode.com, and I request a.com, the plugin will request b.com and do the processing, now the processing is successful but there is no response content from luacode.com.

package plugins

import (
    "encoding/json"
    "fmt"
    pkgHTTP "github.com/apache/apisix-go-plugin-runner/pkg/http"
    "github.com/apache/apisix-go-plugin-runner/pkg/log"
    "github.com/apache/apisix-go-plugin-runner/pkg/plugin"
    "github.com/sirupsen/logrus"
    "net/http"
    "time"
)

func init() {
    err := plugin.RegisterPlugin(&ForwardAuth{})
    if err != nil {
        log.Fatalf("failed to register plugin ForwardAuth: %s", err)
    }
}

// ForwardAuth is a demo to show how to return data directly instead of proxying
// it to the upstream.
type ForwardAuth struct {
}

type ForwardAuthConf struct {
    Body string `json:"body"`
}

func (p *ForwardAuth) Name() string {
    return "forward-auth"
}

func (p *ForwardAuth) ParseConf(in []byte) (interface{}, error) {
    conf := ForwardAuthConf{}
    err := json.Unmarshal(in, &conf)
    return conf, err
}
func (p *ForwardAuth) Filter(conf interface{}, w http.ResponseWriter, r pkgHTTP.Request) {
    req, err := http.NewRequest("GET", "http://b.com", nil)
    if err != nil {
        logrus.Errorf("send request failed err:%v", err)
        return
    }
    //req.Header.Set("Cookie", r.Header().Get("Cookie"))
    client := http.Client{
        Timeout: 5 * time.Second,
    }
    resp, err := client.Do(req)
    if err != nil {
        logrus.Errorf("get response failed err:%v", err)
        return
    }
    if resp == nil {
        logrus.Errorf("response is nil")
        return
    }
    defer resp.Body.Close()

    if len(resp.Header) > 0 {
        for k, v := range resp.Header {
            if v != nil {
                w.Header().Set(k, v[0])
            }
        }
    }

    w.Header().Add("X-Resp-A6-Runner", "Go")
    return

}

not use plugin image after use pulgin image

GhangZh commented 2 years ago

1.I found that after I use core.response.set_header(k, v) then the response body of the service I requested was empty. 2.What do you mean by this? @spacewander

  1. you can stop the request with headers, see https://github.com/apache/apisix-go-plugin-runner/blob/195bd64e4d0edeb471a43016f0c3f0dad59f86b9/cmd/go-runner/plugins/say.go#L61
  2. currently, there is no way to set response header without stopping the request (the core.response.set_header(k, v) in your example). Maybe you can open an issue to track it?
spacewander commented 2 years ago

Currently, setting response data will mean stopping the current process and returning immediately without proxying the request to upstream.

GhangZh commented 2 years ago

Currently, setting response data will mean stopping the current process and returning immediately without proxying the request to upstream.

How should I change to proxy the request to upstream ? I've tried both severless-plugin and go-plugin-runner plugins to support forward-auth,But none of these are currently met, And not having this plugin would cause all our services not being accessible

shuaijinchao commented 2 years ago

@GhangZh try w.Header().Add("X-Resp-A6-Runner", "Go") change to r.Header().Set("X-Resp-A6-Runner", "Go")

GhangZh commented 2 years ago

Thanks, change to r.Header().Set("X-Resp-A6-Runner", "Go") solved my problem