router.go 7.1 KB
Newer Older
Y
Your Name 已提交
1
package gokunode
E
eoLinker API Management 已提交
2 3 4 5

import (
	"fmt"

黄孟柱 已提交
6 7 8 9
	log "github.com/eolinker/goku-api-gateway/goku-log"
	access_log "github.com/eolinker/goku-api-gateway/goku-node/access-log"
	"github.com/eolinker/goku-api-gateway/goku-node/handler"
	"github.com/eolinker/goku-api-gateway/goku-node/plugin-flow"
Y
Your Name 已提交
10
	access_field "github.com/eolinker/goku-api-gateway/server/access-field"
E
eoLinker API Management 已提交
11 12 13 14 15
	"net/http"
	"strconv"
	"strings"
	"time"

黄孟柱 已提交
16 17
	"github.com/eolinker/goku-api-gateway/goku-node/common"
	monitor_write "github.com/eolinker/goku-api-gateway/server/monitor/monitor-write"
E
eoLinker API Management 已提交
18

黄孟柱 已提交
19 20 21 22 23 24 25
	gateway_manager "github.com/eolinker/goku-api-gateway/goku-node/manager/gateway-manager"
	strategy_api_manager "github.com/eolinker/goku-api-gateway/goku-node/manager/strategy-api-manager"
	strategy_api_plugin_manager "github.com/eolinker/goku-api-gateway/goku-node/manager/strategy-api-plugin-manager"
	strategy_plugin_manager "github.com/eolinker/goku-api-gateway/goku-node/manager/strategy-plugin-manager"
	node_common "github.com/eolinker/goku-api-gateway/goku-node/node-common"
	"github.com/eolinker/goku-api-gateway/goku-node/visit"
	entity "github.com/eolinker/goku-api-gateway/server/entity/node-entity"
E
eoLinker API Management 已提交
26 27 28
	// "time"
)

Y
Your Name 已提交
29
// Router 路由
E
eoLinker API Management 已提交
30 31 32 33
type Router struct {
	mu map[string]http.HandlerFunc
}

Y
Your Name 已提交
34
func (mux *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
E
eoLinker API Management 已提交
35 36 37 38 39 40 41
	if r.RequestURI == "*" {
		if r.ProtoAtLeast(1, 1) {
			w.Header().Set("Connection", "close")
		}
		w.WriteHeader(http.StatusBadRequest)
		return
	}
Y
Your Name 已提交
42 43 44
	path := r.URL.Path
	h, has := mux.mu[path]
	if has {
E
eoLinker API Management 已提交
45 46 47
		h.ServeHTTP(w, r)
		return
	}
Y
Your Name 已提交
48
	ServeHTTP(w, r)
E
eoLinker API Management 已提交
49 50 51

}

Y
Your Name 已提交
52
// NewRouter 创建新路由
E
eoLinker API Management 已提交
53 54
func NewRouter() http.Handler {

Y
Your Name 已提交
55 56
	r := &Router{
		mu: make(map[string]http.HandlerFunc),
E
eoLinker API Management 已提交
57 58
	}

Y
Your Name 已提交
59
	hs := handler.Handler()
E
eoLinker API Management 已提交
60

Y
Your Name 已提交
61
	for _, h := range hs {
E
eoLinker API Management 已提交
62 63 64
		r.mu[h.Pattern] = h.HandlerFunc
	}

Y
Your Name 已提交
65
	return r
E
eoLinker API Management 已提交
66 67 68 69
}

var systemRequestPath = []string{"/oauth2/token", "/oauth2/authorize", "/oauth2/verify"}

Y
Your Name 已提交
70
//ServeHTTP httpHandle
Y
Your Name 已提交
71
func ServeHTTP(w http.ResponseWriter, req *http.Request) {
E
eoLinker API Management 已提交
72 73 74 75 76 77
	defer func() {
		if err := recover(); err != nil {
			log.Warn(err)
		}
	}()

Y
Your Name 已提交
78
	timeStart := time.Now()
E
eoLinker API Management 已提交
79

Y
Your Name 已提交
80
	logFields := make(log.Fields)
E
eoLinker API Management 已提交
81 82 83 84 85 86 87

	// 记录访问次数
	requestID := GetRandomString(16)

	ctx := common.NewContext(req, requestID, w)
	proxyStatusCode := 0

Y
Your Name 已提交
88 89 90 91 92 93
	log.Debug(requestID, " url: ", req.URL.String())
	log.Debug(requestID, " header: ", ctx.RequestOrg.Header.String())
	rawBody, err := ctx.RequestOrg.RawBody()
	if err == nil {
		log.Debug(requestID, " body: ", string(rawBody))
	}
E
eoLinker API Management 已提交
94 95

	defer func() {
Y
Your Name 已提交
96
		n, status := ctx.Finish()
E
eoLinker API Management 已提交
97 98 99 100

		if ctx.ProxyResponseHandler != nil {
			proxyStatusCode = ctx.ProxyResponseHandler.StatusCode()
		}
Y
Your Name 已提交
101 102 103 104 105 106 107 108
		logFields[access_field.RequestID] = requestID
		logFields[access_field.StatusCode] = status
		logFields[access_field.HTTPUserAgent] = fmt.Sprint("\"", req.UserAgent(), "\"")
		logFields[access_field.HTTPReferer] = req.Referer()
		logFields[access_field.RequestTime] = time.Since(timeStart)
		logFields[access_field.Request] = fmt.Sprint("\"", req.Method, " ", req.URL.Path, " ", req.Proto, "\"")
		logFields[access_field.BodyBytesSent] = n
		logFields[access_field.Host] = req.Host
E
eoLinker API Management 已提交
109 110 111 112 113 114 115 116
		access_log.Log(logFields)
		log.WithFields(logFields).Info()

		for _, path := range systemRequestPath {
			if path == req.URL.Path {
				return
			}
		}
Y
Your Name 已提交
117
		apiID := strconv.Itoa(ctx.ApiID())
E
eoLinker API Management 已提交
118

Y
Your Name 已提交
119
		monitor_write.AddMonitor(ctx.StrategyId(), apiID, proxyStatusCode, ctx.StatusCode())
E
eoLinker API Management 已提交
120 121 122
	}()

	remoteAddr := Intercept(req.RemoteAddr, ":")
Y
Your Name 已提交
123
	logFields[access_field.RemoteAddr] = remoteAddr
E
eoLinker API Management 已提交
124

Y
Your Name 已提交
125
	if realIP := ctx.GetHeader("X-Real-Ip"); realIP == "" {
E
eoLinker API Management 已提交
126
		ctx.ProxyRequest.SetHeader("X-Real-Ip", remoteAddr)
Y
Your Name 已提交
127
		logFields[access_field.HTTPXForwardedFor] = remoteAddr
Y
Your Name 已提交
128
	} else {
Y
Your Name 已提交
129
		logFields[access_field.HTTPXForwardedFor] = realIP
E
eoLinker API Management 已提交
130 131 132 133 134
	}

	// 匹配URI前执行函数
	var isBefor bool
	start := time.Now()
Y
Your Name 已提交
135
	isBefor = pluginflow.BeforeMatch(ctx)
Y
Your Name 已提交
136
	log.Info(requestID, " BeforeMatch plugin duration:", time.Since(start))
E
eoLinker API Management 已提交
137
	if !isBefor {
Y
Your Name 已提交
138
		log.Info(requestID, " stop by BeforeMatch plugin")
E
eoLinker API Management 已提交
139 140 141 142 143 144 145 146 147 148
		return
	}

	var timeout, retryCount int

	strategyID, ok := retrieveStrategyID(ctx)
	if !ok {
		return
	}

Y
Your Name 已提交
149
	logFields[access_field.Strategy] = fmt.Sprintf("\"%s %s\"", strategyID, ctx.StrategyName())
E
eoLinker API Management 已提交
150 151 152 153 154

	requestPath := req.URL.Path
	requestMenthod := ctx.Request().Method()

	var handleFunc []*entity.PluginHandlerExce
Y
Your Name 已提交
155
	apiInfo, splitURL, param, ok := strategy_api_manager.CheckAPIFromStrategy(strategyID, requestPath, req.Method)
E
eoLinker API Management 已提交
156
	if ok {
Y
Your Name 已提交
157
		ctx.SetAPIID(apiInfo.APIID)
E
eoLinker API Management 已提交
158 159 160 161 162 163
		retryCount = apiInfo.RetryCount
		//ctx.IsMatch = true
		timeout = apiInfo.Timeout

		ctx.ProxyRequest.SetTargetServer(fmt.Sprintf("%s://%s", apiInfo.Protocol, apiInfo.Target))

Y
Your Name 已提交
164
		targetURL := apiInfo.TargetURL + requestPath
E
eoLinker API Management 已提交
165 166

		if apiInfo.StripPrefix {
Y
Your Name 已提交
167
			targetURL = apiInfo.TargetURL + splitURL
E
eoLinker API Management 已提交
168 169
		}
		if apiInfo.StripSlash {
Y
Your Name 已提交
170
			targetURL = node_common.FilterSlash(targetURL)
E
eoLinker API Management 已提交
171 172 173 174
		}
		if !apiInfo.IsFollow {
			ctx.ProxyRequest.Method = strings.ToUpper(apiInfo.TargetMethod)
		}
Y
Your Name 已提交
175
		targetURL = node_common.MatchRestful(targetURL, param)
E
eoLinker API Management 已提交
176

Y
Your Name 已提交
177
		ctx.ProxyRequest.SetTargetURL(targetURL)
E
eoLinker API Management 已提交
178

Y
Your Name 已提交
179
		handleFunc, _ = strategy_api_plugin_manager.GetPluginsOfAPI(strategyID, apiInfo.APIID)
E
eoLinker API Management 已提交
180 181 182 183 184

	} else {
		handleFunc, _ = strategy_plugin_manager.GetPluginsOfStrategy(strategyID)
	}
	start = time.Now()
Y
Your Name 已提交
185
	isAccess, _ := pluginflow.AccessFunc(ctx, handleFunc)
Y
Your Name 已提交
186
	log.Info(requestID, " Access plugin duration:", time.Since(start))
E
eoLinker API Management 已提交
187 188 189 190 191 192 193
	if !isAccess {

		// todo
		return
	}

	if apiInfo == nil {
Y
Your Name 已提交
194
		log.Info(requestID, " URL dose not exist!")
E
eoLinker API Management 已提交
195 196
		ctx.SetStatus(404, "404")
		ctx.SetBody([]byte("[ERROR]URL dose not exist!"))
Y
Your Name 已提交
197

E
eoLinker API Management 已提交
198 199
		return
	}
Y
Your Name 已提交
200 201 202
	logFields[access_field.API] = fmt.Sprintf("\"%d %s\"", apiInfo.APIID, apiInfo.APIName)
	logFields[access_field.Proxy] = fmt.Sprintf("\"%s %s %s\"", ctx.ProxyRequest.Method, ctx.ProxyRequest.TargetURL(), apiInfo.Protocol)
	logFields[access_field.Balance] = apiInfo.Target
E
eoLinker API Management 已提交
203
	start = time.Now()
Y
Your Name 已提交
204
	response, err := CreateRequest(ctx, apiInfo, timeout, retryCount)
Y
Your Name 已提交
205
	log.Info(requestID, " Proxy request duration:", time.Since(start))
E
eoLinker API Management 已提交
206
	if err != nil {
Y
Your Name 已提交
207
		log.Warn(err.Error())
E
eoLinker API Management 已提交
208
	}
Y
Your Name 已提交
209 210
	logFields[access_field.FinallyServer] = ctx.FinalTargetServer()
	logFields[access_field.Retry] = ctx.RetryTargetServers()
E
eoLinker API Management 已提交
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
	ctx.SetProxyResponse(response)
	form, _ := ctx.RequestOrg.BodyForm()
	if response == nil {
		proxyStatusCode = -1
		// ctx.Proxy
		go visit.UpdateProxyFailureCount(apiInfo,
			requestMenthod, ctx.ProxyRequest.Method,
			ctx.RequestOrg.Headers(),
			ctx.RequestOrg.URL().Query(),
			form,
			504,
			make(map[string][]string),

			ctx)
	} else {
Y
Your Name 已提交
226
		logFields[access_field.ProxyStatusCode] = response.StatusCode
E
eoLinker API Management 已提交
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
		// w.WriteHeader(ctx.ProxyStatusCode)
		if !gateway_manager.IsSucess(ctx.StatusCode()) {
			go visit.UpdateProxyFailureCount(
				apiInfo,
				requestMenthod,
				ctx.ProxyRequest.Method,
				ctx.RequestOrg.Headers(),
				ctx.RequestOrg.URL().Query(),
				form,
				ctx.ProxyResponseHandler.StatusCode(),
				ctx.ProxyResponseHandler.Headers(),
				ctx)
		}
	}

	start = time.Now()
Y
Your Name 已提交
243
	isProxy, _ := pluginflow.ProxyFunc(ctx, handleFunc)
Y
Your Name 已提交
244
	log.Info(requestID, " Proxy plugin Duration:", time.Since(start))
E
eoLinker API Management 已提交
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
	if !isProxy {
		return
	}
	// 默认返回插件未开启时,直接返回回复相关内容
	if response != nil {

	} else {
		ctx.SetStatus(504, "504")
		ctx.SetBody([]byte("[ERROR]Fail to get response after proxy!"))
	}

	//logFunc(ctx, handleFunc)

	return
}