github.com/searKing/golang/go@v1.2.74/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 //go:generate go-option -type "HandlerInterceptorChain" 22 type HandlerInterceptorChain struct { 23 interceptors []internal.HandlerInterceptor 24 } 25 26 func NewHandlerInterceptorChain(opts ...HandlerInterceptorChainOption) *HandlerInterceptorChain { 27 chain := &HandlerInterceptorChain{} 28 chain.ApplyOptions(opts...) 29 return chain 30 } 31 32 // InjectHttpHandler returns a http handler injected by chain 33 func (chain HandlerInterceptorChain) InjectHttpHandler(next http.Handler) http.Handler { 34 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 35 // short circuit 36 if len(chain.interceptors) == 0 { 37 next.ServeHTTP(w, r) 38 return 39 } 40 41 // record where to reverse 42 var it = -1 43 defer func() { 44 defer func() { 45 err := recover() 46 // no filter 47 if it == -1 { 48 panic(err) 49 } 50 for i := it; i >= 0; i-- { 51 chain.interceptors[i].AfterCompletion(w, r, err) 52 } 53 }() 54 if err := recover(); err != nil { 55 panic(err) 56 } 57 for i := it; i >= 0; i-- { 58 chain.interceptors[i].PostHandle(w, r) 59 } 60 }() 61 62 for i, filter := range chain.interceptors { 63 err := filter.PreHandle(w, r) 64 if err != nil { 65 // assumes that this interceptor has already dealt with the response itself 66 return 67 } 68 // the execution chain should proceed with the next interceptor or the handler itself 69 it = i 70 } 71 72 for i := range chain.interceptors { 73 next = chain.interceptors[len(chain.interceptors)-1-i].WrapHandle(next) 74 } 75 76 next.ServeHTTP(w, r) 77 }) 78 79 }