2024-12-28 12:26:36 +00:00
|
|
|
// Package apis for http
|
|
|
|
package rest
|
|
|
|
|
|
|
|
import (
|
2024-12-28 12:55:54 +00:00
|
|
|
"context"
|
2024-12-28 12:26:36 +00:00
|
|
|
"fmt"
|
|
|
|
"log/slog"
|
|
|
|
"net/http"
|
|
|
|
"path/filepath"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/go-chi/chi/v5/middleware"
|
|
|
|
|
|
|
|
"git.ifooth.com/common/pkg/http/httpserver"
|
|
|
|
"git.ifooth.com/common/pkg/http/restyclient"
|
|
|
|
)
|
|
|
|
|
2024-12-28 12:55:54 +00:00
|
|
|
// RequestID reuqest_id
|
|
|
|
func RequestID(next http.Handler) http.Handler {
|
|
|
|
fn := func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
requestID := r.Header.Get(requestIDHeaderKey)
|
|
|
|
if requestID == "" {
|
|
|
|
requestID = GenRequestID()
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = WithRequestID(ctx, requestID)
|
|
|
|
ctx = context.WithValue(ctx, middleware.RequestIDKey, requestID)
|
|
|
|
|
|
|
|
w.Header().Set(requestIDHeaderKey, requestID)
|
|
|
|
next.ServeHTTP(w, r.WithContext(ctx))
|
|
|
|
}
|
|
|
|
return http.HandlerFunc(fn)
|
|
|
|
}
|
|
|
|
|
2024-12-28 12:26:36 +00:00
|
|
|
// HandleLogger 记录请求日志
|
|
|
|
func HandleLogger(next http.Handler) http.Handler {
|
|
|
|
fn := func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
st := time.Now()
|
|
|
|
|
|
|
|
// 优先使用蓝鲸网关的request_id
|
|
|
|
reqId := r.Header.Get("X-Bkapi-Request-ID")
|
|
|
|
if reqId == "" {
|
|
|
|
reqId = r.Header.Get("X-Request-Id")
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := restyclient.WithRequestID(r.Context(), reqId)
|
|
|
|
r = r.WithContext(ctx)
|
|
|
|
|
|
|
|
limit := 2048
|
|
|
|
reqBuf := httpserver.NewLimitBuffer(limit)
|
|
|
|
r.Body = httpserver.TeeReadCloser(r.Body, reqBuf)
|
|
|
|
|
|
|
|
ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)
|
|
|
|
respBuf := httpserver.NewLimitBuffer(limit)
|
|
|
|
ww.Tee(respBuf)
|
|
|
|
|
|
|
|
next.ServeHTTP(ww, r)
|
|
|
|
|
|
|
|
// 保证能读取前1K字符
|
|
|
|
// if reqBuf.Remain() > 0 {
|
|
|
|
// io.Copy(io.Discard, io.LimitReader(r.Body, int64(reqBuf.Remain())))
|
|
|
|
// }
|
|
|
|
|
|
|
|
msg := fmt.Sprintf("Handle %s %s From %s", r.Method, r.RequestURI, r.RemoteAddr)
|
|
|
|
slog.Info(msg, "req_id", reqId, "status", ww.Status(), "duration", time.Since(st), "req", reqBuf.String(), "resp", respBuf.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
return http.HandlerFunc(fn)
|
|
|
|
}
|
|
|
|
|
|
|
|
// AuthRequired API类型, 兼容多种鉴权模式
|
|
|
|
func AuthRequired(next http.Handler) http.Handler {
|
|
|
|
ignoreExtMap := map[string]struct{}{
|
|
|
|
".js": {},
|
|
|
|
".css": {},
|
|
|
|
".map": {},
|
|
|
|
".png": {},
|
|
|
|
}
|
|
|
|
|
|
|
|
fn := func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if r.Method == http.MethodOptions {
|
|
|
|
next.ServeHTTP(w, r)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// 静态资源过滤, 注意不会带鉴权信息
|
|
|
|
fileExt := filepath.Ext(r.URL.Path)
|
|
|
|
if _, ok := ignoreExtMap[fileExt]; ok {
|
|
|
|
next.ServeHTTP(w, r)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// switch {
|
|
|
|
// default:
|
|
|
|
// render.Render(w, r, rest.AbortWithUnauthorizedError(rest.UnauthorizedError))
|
|
|
|
// return
|
|
|
|
// }
|
|
|
|
|
|
|
|
next.ServeHTTP(w, r)
|
|
|
|
}
|
|
|
|
return http.HandlerFunc(fn)
|
|
|
|
}
|