ghttp_request_middleware.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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. package ghttp
  7. import (
  8. "github.com/gogf/gf/errors/gcode"
  9. "github.com/gogf/gf/errors/gerror"
  10. "net/http"
  11. "reflect"
  12. "github.com/gogf/gf/util/gutil"
  13. )
  14. // middleware is the plugin for request workflow management.
  15. type middleware struct {
  16. served bool // Is the request served, which is used for checking response status 404.
  17. request *Request // The request object pointer.
  18. handlerIndex int // Index number for executing sequence purpose for handler items.
  19. handlerMDIndex int // Index number for executing sequence purpose for bound middleware of handler item.
  20. }
  21. // Next calls the next workflow handler.
  22. // It's an important function controlling the workflow of the server request execution.
  23. func (m *middleware) Next() {
  24. var item *handlerParsedItem
  25. var loop = true
  26. for loop {
  27. // Check whether the request is exited.
  28. if m.request.IsExited() || m.handlerIndex >= len(m.request.handlers) {
  29. break
  30. }
  31. item = m.request.handlers[m.handlerIndex]
  32. // Filter the HOOK handlers, which are designed to be called in another standalone procedure.
  33. if item.Handler.Type == handlerTypeHook {
  34. m.handlerIndex++
  35. continue
  36. }
  37. // Current router switching.
  38. m.request.Router = item.Handler.Router
  39. // Router values switching.
  40. m.request.routerMap = item.Values
  41. gutil.TryCatch(func() {
  42. // Execute bound middleware array of the item if it's not empty.
  43. if m.handlerMDIndex < len(item.Handler.Middleware) {
  44. md := item.Handler.Middleware[m.handlerMDIndex]
  45. m.handlerMDIndex++
  46. niceCallFunc(func() {
  47. md(m.request)
  48. })
  49. loop = false
  50. return
  51. }
  52. m.handlerIndex++
  53. switch item.Handler.Type {
  54. // Service object.
  55. case handlerTypeObject:
  56. m.served = true
  57. if m.request.IsExited() {
  58. break
  59. }
  60. if item.Handler.InitFunc != nil {
  61. niceCallFunc(func() {
  62. item.Handler.InitFunc(m.request)
  63. })
  64. }
  65. if !m.request.IsExited() {
  66. m.callHandlerFunc(item.Handler.Info)
  67. }
  68. if !m.request.IsExited() && item.Handler.ShutFunc != nil {
  69. niceCallFunc(func() {
  70. item.Handler.ShutFunc(m.request)
  71. })
  72. }
  73. // Service handler.
  74. case handlerTypeHandler:
  75. m.served = true
  76. if m.request.IsExited() {
  77. break
  78. }
  79. niceCallFunc(func() {
  80. m.callHandlerFunc(item.Handler.Info)
  81. })
  82. // Global middleware array.
  83. case handlerTypeMiddleware:
  84. niceCallFunc(func() {
  85. item.Handler.Info.Func(m.request)
  86. })
  87. // It does not continue calling next middleware after another middleware done.
  88. // There should be a "Next" function to be called in the middleware in order to manage the workflow.
  89. loop = false
  90. }
  91. }, func(exception error) {
  92. if e, ok := exception.(errorStack); ok {
  93. // It's already an error that has stack info.
  94. m.request.error = e
  95. } else {
  96. // Create a new error with stack info.
  97. // Note that there's a skip pointing the start stacktrace
  98. // of the real error point.
  99. m.request.error = gerror.WrapCodeSkip(gcode.CodeInternalError, 1, exception, "")
  100. }
  101. m.request.Response.WriteStatus(http.StatusInternalServerError, exception)
  102. loop = false
  103. })
  104. }
  105. // Check the http status code after all handler and middleware done.
  106. if m.request.IsExited() || m.handlerIndex >= len(m.request.handlers) {
  107. if m.request.Response.Status == 0 {
  108. if m.request.Middleware.served {
  109. m.request.Response.WriteHeader(http.StatusOK)
  110. } else {
  111. m.request.Response.WriteHeader(http.StatusNotFound)
  112. }
  113. }
  114. }
  115. }
  116. func (m *middleware) callHandlerFunc(funcInfo handlerFuncInfo) {
  117. niceCallFunc(func() {
  118. if funcInfo.Func != nil {
  119. funcInfo.Func(m.request)
  120. } else {
  121. var inputValues = []reflect.Value{
  122. reflect.ValueOf(m.request.Context()),
  123. }
  124. if funcInfo.Type.NumIn() == 2 {
  125. var (
  126. inputObject reflect.Value
  127. )
  128. if funcInfo.Type.In(1).Kind() == reflect.Ptr {
  129. inputObject = reflect.New(funcInfo.Type.In(1).Elem())
  130. m.request.handlerResponse.Error = m.request.Parse(inputObject.Interface())
  131. } else {
  132. inputObject = reflect.New(funcInfo.Type.In(1).Elem()).Elem()
  133. m.request.handlerResponse.Error = m.request.Parse(inputObject.Addr().Interface())
  134. }
  135. if m.request.handlerResponse.Error != nil {
  136. return
  137. }
  138. inputValues = append(inputValues, inputObject)
  139. }
  140. // Call handler with dynamic created parameter values.
  141. results := funcInfo.Value.Call(inputValues)
  142. switch len(results) {
  143. case 1:
  144. if !results[0].IsNil() {
  145. if err, ok := results[0].Interface().(error); ok {
  146. m.request.handlerResponse.Error = err
  147. }
  148. }
  149. case 2:
  150. m.request.handlerResponse.Object = results[0].Interface()
  151. if !results[1].IsNil() {
  152. if err, ok := results[1].Interface().(error); ok {
  153. m.request.handlerResponse.Error = err
  154. }
  155. }
  156. }
  157. }
  158. })
  159. }