github.com/wangyougui/gf/v2@v2.6.5/net/ghttp/ghttp_request_middleware.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 13 "github.com/wangyougui/gf/v2/errors/gcode" 14 "github.com/wangyougui/gf/v2/errors/gerror" 15 "github.com/wangyougui/gf/v2/util/gutil" 16 ) 17 18 // middleware is the plugin for request workflow management. 19 type middleware struct { 20 served bool // Is the request served, which is used for checking response status 404. 21 request *Request // The request object pointer. 22 handlerIndex int // Index number for executing sequence purpose for handler items. 23 handlerMDIndex int // Index number for executing sequence purpose for bound middleware of handler item. 24 } 25 26 // Next calls the next workflow handler. 27 // It's an important function controlling the workflow of the server request execution. 28 func (m *middleware) Next() { 29 var item *HandlerItemParsed 30 var loop = true 31 for loop { 32 // Check whether the request is excited. 33 if m.request.IsExited() || m.handlerIndex >= len(m.request.handlers) { 34 break 35 } 36 item = m.request.handlers[m.handlerIndex] 37 // Filter the HOOK handlers, which are designed to be called in another standalone procedure. 38 if item.Handler.Type == HandlerTypeHook { 39 m.handlerIndex++ 40 continue 41 } 42 // Current router switching. 43 m.request.Router = item.Handler.Router 44 45 // Router values switching. 46 m.request.routerMap = item.Values 47 48 var ctx = m.request.Context() 49 gutil.TryCatch(ctx, func(ctx context.Context) { 50 // Execute bound middleware array of the item if it's not empty. 51 if m.handlerMDIndex < len(item.Handler.Middleware) { 52 md := item.Handler.Middleware[m.handlerMDIndex] 53 m.handlerMDIndex++ 54 niceCallFunc(func() { 55 md(m.request) 56 }) 57 loop = false 58 return 59 } 60 m.handlerIndex++ 61 62 switch item.Handler.Type { 63 // Service object. 64 case HandlerTypeObject: 65 m.served = true 66 if m.request.IsExited() { 67 break 68 } 69 if item.Handler.InitFunc != nil { 70 niceCallFunc(func() { 71 item.Handler.InitFunc(m.request) 72 }) 73 } 74 if !m.request.IsExited() { 75 m.callHandlerFunc(item.Handler.Info) 76 } 77 if !m.request.IsExited() && item.Handler.ShutFunc != nil { 78 niceCallFunc(func() { 79 item.Handler.ShutFunc(m.request) 80 }) 81 } 82 83 // Service handler. 84 case HandlerTypeHandler: 85 m.served = true 86 if m.request.IsExited() { 87 break 88 } 89 niceCallFunc(func() { 90 m.callHandlerFunc(item.Handler.Info) 91 }) 92 93 // Global middleware array. 94 case HandlerTypeMiddleware: 95 niceCallFunc(func() { 96 item.Handler.Info.Func(m.request) 97 }) 98 // It does not continue calling next middleware after another middleware done. 99 // There should be a "Next" function to be called in the middleware in order to manage the workflow. 100 loop = false 101 } 102 }, func(ctx context.Context, exception error) { 103 if gerror.HasStack(exception) { 104 // It's already an error that has stack info. 105 m.request.error = exception 106 } else { 107 // Create a new error with stack info. 108 // Note that there's a skip pointing the start stacktrace 109 // of the real error point. 110 m.request.error = gerror.WrapCodeSkip(gcode.CodeInternalError, 1, exception, "") 111 } 112 m.request.Response.WriteStatus(http.StatusInternalServerError, exception) 113 loop = false 114 }) 115 } 116 // Check the http status code after all handlers and middleware done. 117 if m.request.IsExited() || m.handlerIndex >= len(m.request.handlers) { 118 if m.request.Response.Status == 0 { 119 if m.request.Middleware.served { 120 m.request.Response.WriteHeader(http.StatusOK) 121 } else { 122 m.request.Response.WriteHeader(http.StatusNotFound) 123 } 124 } 125 } 126 } 127 128 func (m *middleware) callHandlerFunc(funcInfo handlerFuncInfo) { 129 niceCallFunc(func() { 130 funcInfo.Func(m.request) 131 }) 132 }