1. Route configuration
Gin uses a routing library based on Httprouter, which constructs a prefix tree for all routing rules
(1) Basic routes and routing groups
1. Basic routes
package main import ( "net/http" "strings" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/user/:name/*action", Func (c *gin.Context) {name := c.param ("name") // Use Context's Param method to get the API parameter Action := c.param ("action") // Intercepting action = Strings.Trim(action, "/") c. tring(http.statusok, name+" is "+action)})Copy the code
2. Route grouping
Route grouping is used to process multiple routes in a unified manner, such as unified prefix, unified middle, and convenient function division.
package main import ( "github.com/gin-gonic/gin" "fmt" ) func main() { // 1. Logger(), Recovery() R := gin.Default() // Routing group v1 := r.group ("/group") {v1.get ("/login", login) v1.POST("submit", submit) } r.Run(":8080") }Copy the code
(2) To deal with the routing in our own project
1. Split routes
If the project continues to expand and grow, continuing to implement route registration in Main. go will make Main. go very scary, so the split and registration of routes should be planned well at the beginning of the project. I choose to create a new folder to manage router-related configuration, and create router.go as the entrance of route configuration.
- Create router.go as a route configuration entry and add an initialization method
/router/router. Go package Routers Import ("github.com/gin-gonic/gin") // Initialize routes func InitRouter() *gin.Engine {r := gin.New() r.Use(gin.Logger()) r.Use(gin.Recovery()) return r }Copy the code
- In order to facilitate the division of different functions, we managed routes by layer. A new folder API was created under the Router folder to store API-related routes, and index.go was created to import routes, add processing methods, and initialize the contents of this folder in router.go.
/router/api/index.go
package api
import (
"github.com/gin-gonic/gin"
)
func InitApi(r *gin.Engine) {
api := r.Group("/api")
}
Copy the code
/router/router. Go package Routers Import ("github.com/gin-gonic/gin" "Go-server-template/Routers/API") // Initialize the routing FUNc InitRouter() *gin.Engine {r := gin.New() r.us (gin.Logger()) r.us (gin.Recovery()) API.Copy the code
- Create a separate file for each route entry of the different module. For example, if I have a route for the login interface, we can create a new folder userRouter to handle the user-related route, and then create an index.go file under the current module to handle the route. Then create a new auth.go to place the route related to user permission verification
/ router/API/userRouter/index. Go package userRouter import (" github.com/gin-gonic/gin ") / / initialization module routing func UserInitRouter(r *gin.RouterGroup) { userAuth := r.Group("/user-auth") UserAuthRouter(userAuth) }Copy the code
/router/api/userRouter/auth.go package userRouter import ( "github.com/gin-gonic/gin" ) func UserAuthRouter(g *gin.RouterGroup) {g.net ("/login", incoming method)}Copy the code
- If new routes are added, you can add routes in this layout, and the entire route folder directory will look something like this
- At this point, we execute go run main.go, and then access the port where the service is currently started
2. Handle routing entries
After the route is written, we need to initialize the route in the project entry. At this point, we can write this for the moment (because we need to abstract it further later).
/main.go package main import (" FMT ""go-server-template/routers") func main() {// Register routes R := Routers := r.Run(":8080") if err ! = nil {fmt.println (" Server failed to start!" )}}Copy the code
(3) Various route definitions and parameter acquisition
1. GET, POST, PUT, PATCH, DELETE, OPTIONS
r.GET("/routerNameGet", getting)
r.POST("/routerNamePost", posting)
r.PUT("/routerNamePut", putting)
r.DELETE("/routerNameDelete", deleting)
r.PATCH("/routerNamePatch", patching)
r.OPTIONS("/routerNameOptions", options)
Copy the code
2. Parameter acquisition
-
Parameters in the URL
1. /user/:name form r.gate ("/user/:account", Func (c *gin.Context) {account := c.param ("account")}) 2. /user/:account/*action func(c *gin.Context) { account := c.Param("account") action := c.Param("action") })Copy the code
-
GET Parameter obtaining
// Matching URL format: /user? Username =guy&account=123456 r.git ("/user", func(c *gin.Context) {// Use this method to obtain the query parameter to set a default value // return if the query parameter has a value, If no, return the default value. Username := c.faultQuery ("username", "Guy") lastName := c.query ("account") // is c.equest.url.query ().get ("account")})Copy the code
-
Obtaining POST Parameters
type User struct { name string `json:"name"` account int64 `json:"account"` } r.POST("/userInfo", Func (c *gin.Context) {// Get the form parameter message := c.postform ("userName") // Form parameter Nick := c.faultPostForm ("account", "123456") // This method can set the default value, Json := make(map[string]interface{}) // pay attention to the contents of this structure c. binjson (&json) log.printf ("%v",&json) // Json := User{} c.binjson (&json)})Copy the code
-
Gets the request header parameters
For example token := c. getheader ("token")Copy the code
Second, middleware configuration
(1) What is middleware
Gin framework allows developers to add user’s own Hook functions in the process of processing requests. This hook function is called middleware, which is suitable for handling common business logic such as login authentication, permission verification, data paging, logging, time statistics, and so on
Gin’s middleware is essentially an anonymous callback function. This is essentially the same as binding a handler to a path.
1. Processing sequence of GIN middleware
Gin’s middleware is an Onion model, just like egg.js’s framework
A simple representation is the following:
The center of the model is the main handler that will eventually process the request, and the other is called the Middleware handler. Each middleware handle can be divided into two parts: incoming requests on the left and outgoing requests on the right. The dividing point is next, and the essence is to execute the function chain through this Next. Each middleware conforms to the principle of first in, last out
(2) How to define middleware
** Note: Middleware in Gin must be a Gin.HandlerFunc type
1. Gin built-in middleware
When developing Web applications using the Gin framework, custom middleware is often required; however, Gin also has some built-in middleware that we can use directly, which will not be described here
func BasicAuth(accounts Accounts) HandlerFunc func BasicAuthForRealm(accounts Accounts, Realm String) HandlerFunc func Bind(Val interface{}) HandlerFunc // intercepts request parameters and binds func ErrorLogger() HandlerFunc // error log handling Func ErrorLoggerT(typ ErrorType) HandlerFunc // Error log handling of custom types func Logger() HandlerFunc // Log recording func LoggerWithConfig(conf) LoggerConfig) HandlerFunc func LoggerWithFormatter(f LogFormatter) HandlerFunc func LoggerWithWriter(out io.Writer, notlogged ... string) HandlerFunc func Recovery() HandlerFunc func RecoveryWithWriter(out io.Writer) HandlerFunc func WrapF(f Http.handlerfunc) HandlerFunc // Wraps http.handlerFunc as middleware func WrapH(h http.handler) HandlerFunc // wraps http.handler as middlewareCopy the code
2. Global middleware
Global middleware works on all routes, and all routing requests need to pass through these global middleware.
Ex. :
Package main import (" FMT ""time" "github.com/gin-gonic/gin") // Define MiddleWare func MiddleWare() gin.HandlerFunc {return Func (c *gin.Context) {t := time.now () fmt.println (" Middleware is executing ") // Set the variable to the key of the Context, Get() := c.set ("request", "middleware ") status := c.whiter.status () fmt.println (" middleware completes ", status) t2 := time.Since(t) fmt.Println("time:", t2) } } func main() { // 1. Recovery() r := gin.Default() // Register middleware for global middleware. Use register R.use (MiddleWare()) // {} for code specification {r.git ("/ce", func(c * gin-.context) {// Value req, _ : be sad et (" request ") FMT. Chtistina georgina rossetti.british poetess = Println (" request ", the req) / / page receive SAN Antonio SON (200, gin. H {" request ": the req})})} r.R UN ()}Copy the code
Source: GIN documentation
3. Local middleware
Package main import (" FMT ""time" "github.com/gin-gonic/gin") // Define MiddleWare func MiddleWare() gin.HandlerFunc {return Func (c *gin.Context) {t := time.now () fmt.println (" Middleware is executing ") // Set the variable to the key of the Context, Get() to Get c. set ("request", "middleware ") // execute function c. ext() // Middleware completes some subsequent things status := c.whiter.status () fmt.println (" middleware completes ", status) t2 := time.Since(t) fmt.Println("time:", t2) } } func main() { // 1. Recovery() R := gin.Default() // Local middle keys use R.et ("/ce", MiddleWare(), Func (c *gin.Context) {// The value req, _ := c.et ("request") fmt.Println("request:", req) // the page receives c.son (200, gin.H{"request": req}) }) r.Run() }Copy the code
Source: GIN documentation
Note 1: In the GIN framework, any number of middleware can be added for each route, and values can be taken across middleware.
Note 2: Gin-.default () uses Logger and Recovery middleware by Default, where: Logger middleware writes logs to gin-.defaultwriter, even if GIN_MODE=release is configured. Recovery middleware will recover any panic. If there is panic, a 500 response code will be written. If you don’t want to use either of the default middleware, you can use gin-.new () to create a New route without any default middleware.
** Note 3:** When starting a new Goroutine in middleware or handler, the original Context (c * gin-.context) cannot be used, but a read-only copy of it (C.copy ()) must be used.
Middleware Recommendation
(3) The value of middleware
1. Get the parameters in the request
Just get it from the return method, as in the routing section above, for example, the parameters in the request header
HandlerFunc {return func(c *gin.Context) {token := c.getheader ("token")}}Copy the code
2. Store values across middleware
After we intercept and preprocess the data in the middleware, if we want to pass the data to the method we defined to process the request, we can use the Set() method in gin-.context. Set() is used to store any type of data through a key that can be retrieved by the next layer of middleware or processing methods using the Get method of gin.Context.
func MiddleWare() gin.HandlerFunc { return func(c *gin.Context) { c.Set("request", "Middleware ") c.ext ()}} func MiddleWare2() gin.HandlerFunc {return func(c *gin.Context) {c.et ("request")}}Copy the code
When we use the Set method to Set the value of the corresponding data type, we can also obtain the value of the corresponding data type through a special method
func (c *Context) GetString(key string) (s string)
func (c *Context) GetStringMap(key string) (sm map[string]interface{})
func (c *Context) GetStringMapString(key string) (sms map[string]string)
func (c *Context) GetStringMapStringSlice(key string) (smss map[string][]string)
func (c *Context) GetStringSlice(key string) (ss []string)
func (c *Context) GetBool(key string) (b bool)
func (c *Context) GetDuration(key string) (d time.Duration)
func (c *Context) GetFloat64(key string) (f64 float64)
func (c *Context) GetInt(key string) (i int)
func (c *Context) GetInt64(key string) (i64 int64)
func (c *Context) GetTime(key string) (t time.Time)
Copy the code
(4) Request interception
1. Front intercept
Without a doubt, request interception is the most important function for middleware. If you are like me, you can substitute the role of route guard for vue-Router.
So what can we do if we think there’s something wrong with the user’s request and we don’t want him to do the next step?
Gin’s Abort series of functions helps us do this. Note that error handling requests return with c.abort, not just a return
func (c *Context) Abort()
func (c *Context) AbortWithStatus(code int)
func (c *Context) AbortWithStatusJSON(code int, jsonObj interface{})
func (c *Context) AbortWithError(code int, err error)
Copy the code
Abort()
Abort prevents suspension of a function in the called function. Note that this will not stop the current function, so it must be eaten with return. For example, you have an Authorization middleware that verifies that the current request is authenticated. If validation fails (for example, passwords do not match), Abort is called to ensure that other functions of the request are not called.
Using Abort() to interrupt a request, 200 is returned directly, but there is no data in the body of the response.
AbortWithStatusJSON()
The AbortWithStatusJSON() method returns data in JSON format after the user request is interrupted
2. Rear intercept
Gin.Context’s Next() method, which can be processed after the request arrives and the business process is completed by middleware post-intercept processing
Such as:
Func Middleware1(c * gin-.context){fmt.println ("1 starts ") // c.ext () will skip the subsequent logic of the current middleware, like defer, Finally, execute the logic after c.ext // multiple c.ext () who comes first and who comes after, much like defer, Func Middleware2(c *gin.Context){fmt.println ("2 start ") c.ext () fmt.println ("2 start ") } r.usse (Middleware1, Middleware2) r.get ("/", Func (c *gin.Context) {c.ext () fmt.println (" method execution ")}) prints 1 start 2 start method execution 2 end 1 endCopy the code
Next() is called to execute the Next middleware action or custom processing method, which simply means to proceed to the Next one.
(5) Define the global middleware in the project
-
As usual, we create a folder in the root directory for middleware, then create a global folder for our defined global middleware and a Custom folder for our local middleware
-
Create a new sample middleware folder auth under Global and create auth.go in the folder
/ middleware/global/auth/auth. Go package AuthMiddleware import (" github.com/gin-gonic/gin ") / / users check func UserAuth () Return func(c *gin.Context) {// Middleware logic}}Copy the code
-
Introduce this middleware in main.go and use it
package main import ( "fmt" "go-server-template/middleware/global/auth" "go-server-template/routers" ) func main() { r := routers.InitRouter() r.Use(authMiddleware.UserAuth()) err := r.Run(":8080") if err ! = nil {fmt.println (" Server failed to start!" )}}Copy the code