github.com/gogf/gf@v1.16.9/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  	"github.com/gogf/gf/debug/gdebug"
    11  	"net/http"
    12  	"reflect"
    13  )
    14  
    15  // BindHookHandler registers handler for specified hook.
    16  func (s *Server) BindHookHandler(pattern string, hook string, handler HandlerFunc) {
    17  	s.doBindHookHandler(pattern, hook, handler, "")
    18  }
    19  
    20  func (s *Server) doBindHookHandler(pattern string, hook string, handler HandlerFunc, source string) {
    21  	s.setHandler(pattern, &handlerItem{
    22  		Type: handlerTypeHook,
    23  		Name: gdebug.FuncPath(handler),
    24  		Info: handlerFuncInfo{
    25  			Func: handler,
    26  			Type: reflect.TypeOf(handler),
    27  		},
    28  		HookName: hook,
    29  		Source:   source,
    30  	})
    31  }
    32  
    33  func (s *Server) BindHookHandlerByMap(pattern string, hookMap map[string]HandlerFunc) {
    34  	for k, v := range hookMap {
    35  		s.BindHookHandler(pattern, k, v)
    36  	}
    37  }
    38  
    39  // callHookHandler calls the hook handler by their registered sequences.
    40  func (s *Server) callHookHandler(hook string, r *Request) {
    41  	hookItems := r.getHookHandlers(hook)
    42  	if len(hookItems) > 0 {
    43  		// Backup the old router variable map.
    44  		oldRouterMap := r.routerMap
    45  		for _, item := range hookItems {
    46  			r.routerMap = item.Values
    47  			// DO NOT USE the router of the hook handler,
    48  			// which can overwrite the router of serving handler.
    49  			// r.Router = item.handler.router
    50  			if err := s.niceCallHookHandler(item.Handler.Info.Func, r); err != nil {
    51  				switch err {
    52  				case exceptionExit:
    53  					break
    54  				case exceptionExitAll:
    55  					fallthrough
    56  				case exceptionExitHook:
    57  					return
    58  				default:
    59  					r.Response.WriteStatus(http.StatusInternalServerError, err)
    60  					panic(err)
    61  				}
    62  			}
    63  		}
    64  		// Restore the old router variable map.
    65  		r.routerMap = oldRouterMap
    66  	}
    67  }
    68  
    69  // getHookHandlers retrieves and returns the hook handlers of specified hook.
    70  func (r *Request) getHookHandlers(hook string) []*handlerParsedItem {
    71  	if !r.hasHookHandler {
    72  		return nil
    73  	}
    74  	parsedItems := make([]*handlerParsedItem, 0, 4)
    75  	for _, v := range r.handlers {
    76  		if v.Handler.HookName != hook {
    77  			continue
    78  		}
    79  		item := v
    80  		parsedItems = append(parsedItems, item)
    81  	}
    82  	return parsedItems
    83  }
    84  
    85  // niceCallHookHandler nicely calls the hook handler function,
    86  // which means it automatically catches and returns the possible panic error to
    87  // avoid goroutine crash.
    88  func (s *Server) niceCallHookHandler(f HandlerFunc, r *Request) (err interface{}) {
    89  	defer func() {
    90  		err = recover()
    91  	}()
    92  	f(r)
    93  	return
    94  }