github.com/gogf/gf/v2@v2.7.4/net/ghttp/ghttp_server_router_hook.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package ghttp
     8  
     9  import (
    10  	"context"
    11  	"net/http"
    12  	"reflect"
    13  
    14  	"github.com/gogf/gf/v2/debug/gdebug"
    15  )
    16  
    17  // BindHookHandler registers handler for specified hook.
    18  func (s *Server) BindHookHandler(pattern string, hook HookName, handler HandlerFunc) {
    19  	s.doBindHookHandler(context.TODO(), doBindHookHandlerInput{
    20  		Prefix:   "",
    21  		Pattern:  pattern,
    22  		HookName: hook,
    23  		Handler:  handler,
    24  		Source:   "",
    25  	})
    26  }
    27  
    28  // doBindHookHandlerInput is the input for BindHookHandler.
    29  type doBindHookHandlerInput struct {
    30  	Prefix   string
    31  	Pattern  string
    32  	HookName HookName
    33  	Handler  HandlerFunc
    34  	Source   string
    35  }
    36  
    37  // doBindHookHandler is the internal handler for BindHookHandler.
    38  func (s *Server) doBindHookHandler(ctx context.Context, in doBindHookHandlerInput) {
    39  	s.setHandler(
    40  		ctx,
    41  		setHandlerInput{
    42  			Prefix:  in.Prefix,
    43  			Pattern: in.Pattern,
    44  			HandlerItem: &HandlerItem{
    45  				Type: HandlerTypeHook,
    46  				Name: gdebug.FuncPath(in.Handler),
    47  				Info: handlerFuncInfo{
    48  					Func: in.Handler,
    49  					Type: reflect.TypeOf(in.Handler),
    50  				},
    51  				HookName: in.HookName,
    52  				Source:   in.Source,
    53  			},
    54  		},
    55  	)
    56  }
    57  
    58  // BindHookHandlerByMap registers handler for specified hook.
    59  func (s *Server) BindHookHandlerByMap(pattern string, hookMap map[HookName]HandlerFunc) {
    60  	for k, v := range hookMap {
    61  		s.BindHookHandler(pattern, k, v)
    62  	}
    63  }
    64  
    65  // callHookHandler calls the hook handler by their registered sequences.
    66  func (s *Server) callHookHandler(hook HookName, r *Request) {
    67  	if !r.hasHookHandler {
    68  		return
    69  	}
    70  	hookItems := r.getHookHandlers(hook)
    71  	if len(hookItems) > 0 {
    72  		// Backup the old router variable map.
    73  		oldRouterMap := r.routerMap
    74  		for _, item := range hookItems {
    75  			r.routerMap = item.Values
    76  			// DO NOT USE the router of the hook handler,
    77  			// which can overwrite the router of serving handler.
    78  			// r.Router = item.handler.router
    79  			if err := s.niceCallHookHandler(item.Handler.Info.Func, r); err != nil {
    80  				switch err {
    81  				case exceptionExit:
    82  					break
    83  				case exceptionExitAll:
    84  					fallthrough
    85  				case exceptionExitHook:
    86  					return
    87  				default:
    88  					r.Response.WriteStatus(http.StatusInternalServerError, err)
    89  					panic(err)
    90  				}
    91  			}
    92  		}
    93  		// Restore the old router variable map.
    94  		r.routerMap = oldRouterMap
    95  	}
    96  }
    97  
    98  // getHookHandlers retrieves and returns the hook handlers of specified hook.
    99  func (r *Request) getHookHandlers(hook HookName) []*HandlerItemParsed {
   100  	parsedItems := make([]*HandlerItemParsed, 0, 4)
   101  	for _, v := range r.handlers {
   102  		if v.Handler.HookName != hook {
   103  			continue
   104  		}
   105  		item := v
   106  		parsedItems = append(parsedItems, item)
   107  	}
   108  	return parsedItems
   109  }
   110  
   111  // niceCallHookHandler nicely calls the hook handler function,
   112  // which means it automatically catches and returns the possible panic error to
   113  // avoid goroutine crash.
   114  func (s *Server) niceCallHookHandler(f HandlerFunc, r *Request) (err interface{}) {
   115  	defer func() {
   116  		err = recover()
   117  	}()
   118  	f(r)
   119  	return
   120  }