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  }