Skip to content

Commit 82568a0

Browse files
authored
route: service gateway (#70)
* route: service gateway Signed-off-by: E99p1ant <i@github.red> * remove debug log Signed-off-by: E99p1ant <i@github.red> --------- Signed-off-by: E99p1ant <i@github.red>
1 parent 19ae315 commit 82568a0

File tree

4 files changed

+106
-0
lines changed

4 files changed

+106
-0
lines changed

internal/conf/conf.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,18 @@ func Init() error {
7070
return errors.Wrap(err, "map 'mail'")
7171
}
7272

73+
serviceSections := File.Section("service").ChildSections()
74+
for _, serviceSection := range serviceSections {
75+
serviceSection := serviceSection
76+
var backend struct {
77+
Prefix string `ini:"prefix"`
78+
ForwardURL string `ini:"forward_url"`
79+
}
80+
if err := serviceSection.MapTo(&backend); err != nil {
81+
return errors.Wrapf(err, "map 'service.%s'", serviceSection.Name())
82+
}
83+
Service.Backends = append(Service.Backends, backend)
84+
}
85+
7386
return nil
7487
}

internal/conf/static.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,11 @@ var (
8383
Port int `ini:"port"`
8484
SMTP string `ini:"smtp"`
8585
}
86+
87+
Service struct {
88+
Backends []struct {
89+
Prefix string `ini:"prefix"`
90+
ForwardURL string `ini:"forward_url"`
91+
}
92+
}
8693
)

internal/route/route.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/wuhan005/NekoBox/route/auth"
3030
"github.com/wuhan005/NekoBox/route/pixel"
3131
"github.com/wuhan005/NekoBox/route/question"
32+
"github.com/wuhan005/NekoBox/route/service"
3233
"github.com/wuhan005/NekoBox/route/user"
3334
"github.com/wuhan005/NekoBox/static"
3435
"github.com/wuhan005/NekoBox/templates"
@@ -141,6 +142,7 @@ func New() *flamego.Flame {
141142
})
142143

143144
f.Any("/pixel/{**}", reqUserSignIn, pixel.Proxy)
145+
f.Any("/service/{**}", service.Proxy)
144146
}, context.APIEndpoint)
145147
},
146148
cache.Cacher(cache.Options{

route/service/proxy.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package service
2+
3+
import (
4+
"crypto/tls"
5+
"net/http"
6+
"net/http/httputil"
7+
"net/url"
8+
"strconv"
9+
"strings"
10+
11+
"github.com/sirupsen/logrus"
12+
"go.opentelemetry.io/otel"
13+
"go.opentelemetry.io/otel/attribute"
14+
"go.opentelemetry.io/otel/propagation"
15+
"go.opentelemetry.io/otel/trace"
16+
17+
"github.com/wuhan005/NekoBox/internal/conf"
18+
"github.com/wuhan005/NekoBox/internal/context"
19+
)
20+
21+
func Proxy(ctx context.Context) error {
22+
span := trace.SpanFromContext(ctx.Request().Context())
23+
24+
var userID uint
25+
if ctx.IsLogged {
26+
userID = ctx.User.ID
27+
}
28+
29+
if span.SpanContext().IsValid() {
30+
span.SetAttributes(
31+
attribute.Int("nekobox.service.user-id", int(userID)),
32+
)
33+
}
34+
35+
uri := ctx.Param("**")
36+
basePath := strings.Split(uri, "/")[0]
37+
forwardPath := strings.TrimPrefix(uri, basePath)
38+
39+
var forwardURLStr string
40+
for _, backend := range conf.Service.Backends {
41+
if backend.Prefix == basePath {
42+
forwardURLStr = backend.ForwardURL
43+
break
44+
}
45+
}
46+
if len(forwardURLStr) == 0 {
47+
return ctx.JSONError(http.StatusNotFound, "页面不存在")
48+
}
49+
50+
forwardURL, err := url.Parse(forwardURLStr)
51+
if err != nil {
52+
logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to parse forward URL")
53+
return ctx.JSONError(http.StatusInternalServerError, "服务网关内部错误")
54+
}
55+
56+
reverseProxy := httputil.ReverseProxy{
57+
Director: func(req *http.Request) {
58+
req.URL = forwardURL
59+
req.URL.Path = strings.TrimRight(req.URL.Path, "/") + forwardPath
60+
req.Host = forwardURL.Host
61+
62+
traceHeaders := http.Header{}
63+
otel.GetTextMapPropagator().Inject(ctx.Request().Context(), propagation.HeaderCarrier(traceHeaders))
64+
for key := range traceHeaders {
65+
req.Header.Set(key, traceHeaders.Get(key))
66+
}
67+
68+
req.Header.Set("X-NekoBox-From", "nekobox-gateway")
69+
req.Header.Set("X-NekoBox-User-ID", strconv.Itoa(int(userID)))
70+
},
71+
Transport: &http.Transport{
72+
TLSClientConfig: &tls.Config{
73+
InsecureSkipVerify: true,
74+
},
75+
},
76+
ErrorHandler: func(writer http.ResponseWriter, request *http.Request, err error) {
77+
logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to handle reverse proxy request")
78+
_ = ctx.JSONError(http.StatusInternalServerError, "服务网关内部错误")
79+
},
80+
}
81+
82+
reverseProxy.ServeHTTP(ctx.ResponseWriter(), ctx.Request().Request)
83+
return nil
84+
}

0 commit comments

Comments
 (0)