github.com/wangyougui/gf/v2@v2.6.5/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/wangyougui/gf. 6 7 package ghttp 8 9 import ( 10 "context" 11 "net/http" 12 "reflect" 13 14 "github.com/wangyougui/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 }