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  }