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  }