fix version 1
This commit is contained in:
@@ -35,12 +35,24 @@ func New(key string, expireSeconds int64, anonymous []string) (*Server, error) {
|
||||
engine.Use(gin.Logger(), gin.Recovery())
|
||||
return &Server{
|
||||
GRPC: grpcServer,
|
||||
Gateway: gwRuntime.NewServeMux(),
|
||||
Gateway: gwRuntime.NewServeMux(gwRuntime.WithRoutingErrorHandler(routeMissHandler)),
|
||||
HTTP: engine,
|
||||
auth: auth,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// routeMissHandler 是 grpc-gateway 的路由错误处理器:只有"路由未命中"才会被标记,
|
||||
// 随后仍按默认行为写出错误体。业务 handler 返回的 NotFound 走的是 errorHandler,
|
||||
// 不会被标记,因而其响应能原样透出而不会被 Gin 的纯文本 404 覆盖。
|
||||
func routeMissHandler(ctx context.Context, mux *gwRuntime.ServeMux, marshaler gwRuntime.Marshaler, w http.ResponseWriter, r *http.Request, httpStatus int) {
|
||||
if httpStatus == http.StatusNotFound {
|
||||
if recorder, ok := w.(routingMissRecorder); ok {
|
||||
recorder.markRoutingMiss()
|
||||
}
|
||||
}
|
||||
gwRuntime.DefaultRoutingErrorHandler(ctx, mux, marshaler, w, r, httpStatus)
|
||||
}
|
||||
|
||||
func (s *Server) Start(grpcAddr, httpAddr string) error {
|
||||
grpcListener, err := net.Listen("tcp", grpcAddr)
|
||||
if err != nil {
|
||||
@@ -60,18 +72,9 @@ func (s *Server) Start(grpcAddr, httpAddr string) error {
|
||||
}
|
||||
s.HTTP.POST("/rpc/:module/:service/:method", s.dynamic.handle)
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
recorder := newBufferedResponse()
|
||||
s.Gateway.ServeHTTP(recorder, r)
|
||||
if recorder.status != http.StatusNotFound {
|
||||
recorder.flush(w)
|
||||
return
|
||||
}
|
||||
s.HTTP.ServeHTTP(w, r)
|
||||
})
|
||||
s.http = &http.Server{
|
||||
Addr: httpAddr,
|
||||
Handler: s.auth.httpMiddleware(handler),
|
||||
Handler: s.auth.httpMiddleware(s.handler()),
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
IdleTimeout: 120 * time.Second,
|
||||
MaxHeaderBytes: 1 << 20,
|
||||
@@ -89,6 +92,21 @@ func (s *Server) Start(grpcAddr, httpAddr string) error {
|
||||
return serveErr
|
||||
}
|
||||
|
||||
// handler 先让 grpc-gateway 处理请求,仅当网关确实未命中路由时才回退到 Gin
|
||||
// (动态 RPC 与原生的 /rest 路由都注册在 Gin 上)。业务返回的 404/NotFound
|
||||
// 属于网关的正常响应,必须原样透出。
|
||||
func (s *Server) handler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
recorder := newBufferedResponse()
|
||||
s.Gateway.ServeHTTP(recorder, r)
|
||||
if !recorder.routingMiss {
|
||||
recorder.flush(w)
|
||||
return
|
||||
}
|
||||
s.HTTP.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) Stop(ctx context.Context) error {
|
||||
stopped := make(chan struct{})
|
||||
go func() {
|
||||
@@ -109,10 +127,17 @@ func (s *Server) Stop(ctx context.Context) error {
|
||||
return s.http.Shutdown(ctx)
|
||||
}
|
||||
|
||||
// routingMissRecorder 由 bufferedResponse 实现,用于区分"网关未命中路由"与业务 NotFound。
|
||||
type routingMissRecorder interface {
|
||||
markRoutingMiss()
|
||||
}
|
||||
|
||||
type bufferedResponse struct {
|
||||
header http.Header
|
||||
body bytes.Buffer
|
||||
status int
|
||||
// routingMiss 表示该 404 来自 grpc-gateway 的路由错误处理,而非业务响应。
|
||||
routingMiss bool
|
||||
}
|
||||
|
||||
func newBufferedResponse() *bufferedResponse {
|
||||
@@ -122,6 +147,7 @@ func newBufferedResponse() *bufferedResponse {
|
||||
func (r *bufferedResponse) Header() http.Header { return r.header }
|
||||
func (r *bufferedResponse) WriteHeader(status int) { r.status = status }
|
||||
func (r *bufferedResponse) Write(data []byte) (int, error) { return r.body.Write(data) }
|
||||
func (r *bufferedResponse) markRoutingMiss() { r.routingMiss = true }
|
||||
func (r *bufferedResponse) flush(w http.ResponseWriter) {
|
||||
for key, values := range r.header {
|
||||
for _, value := range values {
|
||||
|
||||
Reference in New Issue
Block a user