github.com/gogf/gf/v2@v2.7.4/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  	"context"
    11  	"net/http"
    12  
    13  	"github.com/gogf/gf/v2/errors/gcode"
    14  	"github.com/gogf/gf/v2/errors/gerror"
    15  	"github.com/gogf/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  }