github.com/gogf/gf@v1.16.9/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/gogf/gf. 6 7 package ghttp 8 9 import ( 10 "github.com/gogf/gf/errors/gcode" 11 "github.com/gogf/gf/errors/gerror" 12 "net/http" 13 "reflect" 14 15 "github.com/gogf/gf/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 *handlerParsedItem 30 var loop = true 31 for loop { 32 // Check whether the request is exited. 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 gutil.TryCatch(func() { 49 // Execute bound middleware array of the item if it's not empty. 50 if m.handlerMDIndex < len(item.Handler.Middleware) { 51 md := item.Handler.Middleware[m.handlerMDIndex] 52 m.handlerMDIndex++ 53 niceCallFunc(func() { 54 md(m.request) 55 }) 56 loop = false 57 return 58 } 59 m.handlerIndex++ 60 61 switch item.Handler.Type { 62 // Service object. 63 case handlerTypeObject: 64 m.served = true 65 if m.request.IsExited() { 66 break 67 } 68 if item.Handler.InitFunc != nil { 69 niceCallFunc(func() { 70 item.Handler.InitFunc(m.request) 71 }) 72 } 73 if !m.request.IsExited() { 74 m.callHandlerFunc(item.Handler.Info) 75 } 76 if !m.request.IsExited() && item.Handler.ShutFunc != nil { 77 niceCallFunc(func() { 78 item.Handler.ShutFunc(m.request) 79 }) 80 } 81 82 // Service handler. 83 case handlerTypeHandler: 84 m.served = true 85 if m.request.IsExited() { 86 break 87 } 88 niceCallFunc(func() { 89 m.callHandlerFunc(item.Handler.Info) 90 }) 91 92 // Global middleware array. 93 case handlerTypeMiddleware: 94 niceCallFunc(func() { 95 item.Handler.Info.Func(m.request) 96 }) 97 // It does not continue calling next middleware after another middleware done. 98 // There should be a "Next" function to be called in the middleware in order to manage the workflow. 99 loop = false 100 } 101 }, func(exception error) { 102 if e, ok := exception.(errorStack); ok { 103 // It's already an error that has stack info. 104 m.request.error = e 105 } else { 106 // Create a new error with stack info. 107 // Note that there's a skip pointing the start stacktrace 108 // of the real error point. 109 m.request.error = gerror.WrapCodeSkip(gcode.CodeInternalError, 1, exception, "") 110 } 111 m.request.Response.WriteStatus(http.StatusInternalServerError, exception) 112 loop = false 113 }) 114 } 115 // Check the http status code after all handler and middleware done. 116 if m.request.IsExited() || m.handlerIndex >= len(m.request.handlers) { 117 if m.request.Response.Status == 0 { 118 if m.request.Middleware.served { 119 m.request.Response.WriteHeader(http.StatusOK) 120 } else { 121 m.request.Response.WriteHeader(http.StatusNotFound) 122 } 123 } 124 } 125 } 126 127 func (m *middleware) callHandlerFunc(funcInfo handlerFuncInfo) { 128 niceCallFunc(func() { 129 if funcInfo.Func != nil { 130 funcInfo.Func(m.request) 131 } else { 132 var inputValues = []reflect.Value{ 133 reflect.ValueOf(m.request.Context()), 134 } 135 if funcInfo.Type.NumIn() == 2 { 136 var ( 137 inputObject reflect.Value 138 ) 139 if funcInfo.Type.In(1).Kind() == reflect.Ptr { 140 inputObject = reflect.New(funcInfo.Type.In(1).Elem()) 141 m.request.handlerResponse.Error = m.request.Parse(inputObject.Interface()) 142 } else { 143 inputObject = reflect.New(funcInfo.Type.In(1).Elem()).Elem() 144 m.request.handlerResponse.Error = m.request.Parse(inputObject.Addr().Interface()) 145 } 146 if m.request.handlerResponse.Error != nil { 147 return 148 } 149 inputValues = append(inputValues, inputObject) 150 } 151 152 // Call handler with dynamic created parameter values. 153 results := funcInfo.Value.Call(inputValues) 154 switch len(results) { 155 case 1: 156 if !results[0].IsNil() { 157 if err, ok := results[0].Interface().(error); ok { 158 m.request.handlerResponse.Error = err 159 } 160 } 161 162 case 2: 163 m.request.handlerResponse.Object = results[0].Interface() 164 if !results[1].IsNil() { 165 if err, ok := results[1].Interface().(error); ok { 166 m.request.handlerResponse.Error = err 167 } 168 } 169 } 170 } 171 }) 172 }