github.com/searKing/golang/go@v1.2.117/net/http/interceptors.server.go (about) 1 // Copyright 2022 The searKing Author. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package http 6 7 import ( 8 "net/http" 9 10 "github.com/searKing/golang/go/net/http/internal" 11 ) 12 13 // HandlerInterceptorChain interface that allows for customized handler execution chains. 14 // Applications can register any number of existing or custom interceptors for certain groups of handlers, 15 // to add common preprocessing behavior without needing to modify each handler implementation. 16 // A HandlerInterceptor gets called before the appropriate HandlerAdapter triggers the execution of the handler itself. 17 // This mechanism can be used for a large field of preprocessing aspects, e.g. for authorization checks, or common 18 // handler behavior like locale or theme changes. 19 // Its main purpose is to allow for factoring out repetitive handler code. 20 // https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/HandlerInterceptor.html 21 // 22 //go:generate go-option -type "HandlerInterceptorChain" 23 type HandlerInterceptorChain struct { 24 interceptors []internal.HandlerInterceptor 25 } 26 27 func NewHandlerInterceptorChain(opts ...HandlerInterceptorChainOption) *HandlerInterceptorChain { 28 chain := &HandlerInterceptorChain{} 29 chain.ApplyOptions(opts...) 30 return chain 31 } 32 33 // InjectHttpHandler returns a http handler injected by chain 34 func (chain HandlerInterceptorChain) InjectHttpHandler(next http.Handler) http.Handler { 35 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 36 // short circuit 37 if len(chain.interceptors) == 0 { 38 next.ServeHTTP(w, r) 39 return 40 } 41 42 // record where to reverse 43 var it = -1 44 defer func() { 45 defer func() { 46 err := recover() 47 // no filter 48 if it == -1 { 49 panic(err) 50 } 51 for i := it; i >= 0; i-- { 52 chain.interceptors[i].AfterCompletion(w, r, err) 53 } 54 }() 55 if err := recover(); err != nil { 56 panic(err) 57 } 58 for i := it; i >= 0; i-- { 59 chain.interceptors[i].PostHandle(w, r) 60 } 61 }() 62 63 for i, filter := range chain.interceptors { 64 err := filter.PreHandle(w, r) 65 if err != nil { 66 // assumes that this interceptor has already dealt with the response itself 67 return 68 } 69 // the execution chain should proceed with the next interceptor or the handler itself 70 it = i 71 } 72 73 for i := range chain.interceptors { 74 next = chain.interceptors[len(chain.interceptors)-1-i].WrapHandle(next) 75 } 76 77 next.ServeHTTP(w, r) 78 }) 79 80 }