GoWeb

Create a simple Web application

package  main
​
import (
    "fmt"
    "log"
    "net/http"
)
​
// Create a handler function
func handler(w http.ResponseWriter, r *http.Request)  {
    fmt.Fprintln(w, "Hello World", r.URL.Path)
}
​
​
func main(a) {
    
    
    // Map the request address to the handler
    http.HandleFunc("/", handler)
    
    
    // Set the listening port and processor
    // The first argument is the port number. If not set, the default is 80.
    // The second argument is the processor. If it is nil, the server will use the default multiplexer DefaultServerMux
    err := http.ListenAndServe(": 8000".nil)
    iferr ! =nil{
        log.Fatalln("ListenAndServer", err)
    }
​
}
Copy the code

Creating the Go Server

Go provides a series of standard libraries for creating Web servers, and the steps to create a server through Go are simple, You simply call the ListenAndServe function via the NET/HTTP package and pass in the network address and the handler responsible for handling the request as parameters. If the network address parameter is an empty string, the server uses port 80 for network connection by default. If the processor argument is nil, then the server will use the default multiplexer DefaultServeMux. Of course, we can also create a multiplexer by calling the NewServeMux function. After receiving the request, the multiplexer determines which processor to use to process the request according to the URL of the request, and then redirects to the corresponding processor to process the request

Gin Framework quick start

Introduction of gin

Gin is a Web framework written in the Go language. It is an API framework similar to Martini but with better performance, nearly 40 times faster thanks to the use of Httprouter.

Gin installation:

Terminal Enter go get github.com/gin-gonic/gin to install

Every time a new project is created: go mod inti projectName

If failed download reference link: https://www.cnblogs.com/kevin-yang123/p/14799091.html

The first GIN program

package main
​
import (
    "github.com/gin-gonic/gin"
)
​
// Create a handler function
func sayHello(c *gin.Context){
    c.JSON(200,gin.H{   //gin.H is a JSON string
        "message": "hello"})},func main(a) {
    // Return a default routing engine
    r := gin.Default()
    
    // GET: request mode; /hello: request path
    // When the client requests the /hello path with the GET method, the following anonymous function is executed
    r.GET("/hello", sayHello )
​
    // Start the HTTP service at 0.0.0:8080 by default
    r.Run(": 9090")}Copy the code

RESTful API style

REST has nothing to do with technology and represents a software architecture style. REST is an acronym for Representational State Transfer, which translates in Chinese as “Representational State Transfer” or “Representational layer State Transfer.”

In simple terms, REST means that when a client interacts with a Web server, four request methods in the HTTP protocol represent different actions.

Recommended reading www.ruanyifeng.com/blog/2011/0…

  • GETTo get resources
  • POSTTo create a new resource
  • PUTUsed to update resources
  • DELETEUsed to delete a resource.

API programs are RESTful as long as they follow the REST style. Currently, in the architecture of the front and back end separation, the front and back ends basically interact through RESTful apis.

    // GET
    r.GET("/book".func(context *gin.Context){
        context.JSON(http.StatusOK, gin.H{
            "method": "GET",})})// POST
    r.POST("/book".func(context *gin.Context){
        context.JSON(http.StatusOK, gin.H{
            "method": "POST",})})//PUT
    r.PUT("/book".func(context *gin.Context) {
        context.JSON(http.StatusOK, gin.H{
            "method": "PUT",})})//DElETE
    r.DELETE("/book".func(context *gin.Context) {
        context.JSON(http.StatusOK, gin.H{
            "method": "DELETE",})})Copy the code

Gin framework returns JSON

Method 1: Use map. Gin.H is the same
package main
​
import (
    "github.com/gin-gonic/gin"
    "net/http"
)
​
func main(a) {
    // Create a default route
    r := gin.Default()
​
    r.GET("/json1".func(context *gin.Context) {
​
        // Method 1: use map. Gin.H is the same as map
        /*data := map[string]interface{}{ "name" : "LittlePrince", "message" : "helloworld", "age" : 16, } */
        data1 := gin.H{
            "name" : "LittlePrince"."message" : "helloworld"."age" : 16,
        }
        context.JSON(http.StatusOK, data1)
    })
    r.Run(": 9091")}Copy the code

Method 2: Capitalize the first letter of the structure to ensure that the JSON can be retrieved

package main
​
import (
    "github.com/gin-gonic/gin"
    "net/http"
)
​
func main(a) {
    // Create a default route
    r := gin.Default()
​
​
    // Use the tag to customize the structure field
    type msg struct{
        Name string  `json:"name"`
        Message string
        Age int
    }
    r.GET("/json2".func(context *gin.Context) {
        data2 := msg{
            Name: "LittlePringe",
            Message: "hello gin",
            Age: 14,
        }
        context.JSON(http.StatusOK, data2)
    })
​
    r.Run(": 9091")}Copy the code

To obtain parameters

Get the QueryString argument (in the URL)

Querystring refers to the URL, right? Parameters such as /user/search? Username = little prince &address= Sand river. Get the queryString argument to the request as follows:

package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
)
func main(a) {
	r := gin.Default()

	r.GET("/usr/search".func(context *gin.Context) {
		username := context.DefaultQuery("username"."LittlePrince")
		address := context.Query("address")

		// Outputs the JSON result to the caller
		context.JSON(http.StatusOK, gin.H{
			"message" : "ok"."username" : username,
			"address" : address,
		})
	})
	r.Run(": 9091")}Copy the code

Gets the parameters in the form

When the data requested by the front end is submitted via a form, such as sending a POST request to /user/search, the request data can be obtained as follows:

package main
​
import (
    "github.com/gin-gonic/gin"
    "net/http"
)
​
func main(a) {
    r := gin.Default()
    r.POST("/usr/search".func(context *gin.Context) {
        // DefaultPostForm returns the specified default value if no value is retrieved
        //username := context.DefaultPostForm("username", "little prince ")
        username := context.PostForm("username")
        address := context.PostForm("address")
​
        context.JSON(http.StatusOK, gin.H{
            "message" : "ok"."username" : username,
            "address" : address,
        })
    })
​
    r.Run(": 9091")}Copy the code

Gets the parameters of JSON

When the data requested by the front end is submitted via JSON, such as sending a POST request to/JSON, the request parameters can be obtained as follows:

package main
​
import (
    "encoding/json"
    "github.com/gin-gonic/gin"
    "net/http"
)
​
func main(a) {
    r := gin.Default()
​
    r.POST("/json3".func(context *gin.Context) {
        b, _ := context.GetRawData()  // Read the Request data from context.request. Body
        // Define a map or structure
        var m map[string]interface{}
            // deserialize
            _ = json.Unmarshal(b, &m)
​
            context.JSON(http.StatusOK, m)
​
    })
​
    r.Run(": 9091")}Copy the code

Getting the Path parameter

The requested parameters are passed through the URL path, for example: /user/search/ little Prince/Shahe. The parameters in the request URL path are obtained as follows.

package main
​
import (
    "encoding/json"
    "github.com/gin-gonic/gin"
    "net/http"
)
​
func main(a) {
    r := gin.Default()
​
    r.GET("usr/serarch/:username/:address".func(context *gin.Context) {
        username := context.Param("username")
        address := context.Param("address")
​
        // Outputs the result to the caller
        context.JSON(http.StatusOK, gin.H{
            "message" : "ok"."username" : username,
            "address" : address,
        })
    })
​
    r.Run(": 9091")}Copy the code

Automatic parameter binding

In order to obtain request parameters more conveniently and improve development efficiency, we can identify the request data Type based on the content-type of the request and automatically extract QueryString, form, JSON, XML and other parameters in the request into the structure using reflection mechanism. The following example code demonstrates this. ShouldBind() is a powerful way to automatically extract JSON, form, and QueryString data based on the request and bind the values to the specified structure object.

ShouldBind completes the binding by parsing the data in the request in the following order:

  1. If it isGETRequest, use onlyFormBinding engine (query).
  2. If it isPOSTRequest, check firstcontent-typeWhether it isJSONXMLAnd then use it againForm(form-data).

Instance as follows

package main

import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
)

func main(a) {
	r := gin.Default()


	type Login struct {
		User string `form:"user" json:"user" binding:"required"`
		Password string  `form:"password" json:"password" binding:"required"`
	}

	/ / bind Json example ({" user ":" q1mi ", "password" : "123456"})
	r.POST("/loginJson".func(context *gin.Context) {
		var login Login
		// Bind to login
		if err := context.ShouldBind(&login); err == nil{
			fmt.Printf("login info: %#v \n", login)
			context.JSON(http.StatusOK, gin.H{
				"user":     login.User,
				"password": login.Password,
			})
		}else {
			context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}

	})

	// Bind form example (user=q1mi&password=123456)
	r.POST("/loginForm".func(c *gin.Context) {
		var login Login
		ShouldBind() selects its own binder based on the content-type of the request
		if err := c.ShouldBind(&login); err == nil {
			c.JSON(http.StatusOK, gin.H{
				"user":     login.User,
				"password": login.Password,
			})
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}
	})

	// Bind the QueryString example (/loginQuery? user=q1mi&password=123456)
	r.GET("/loginForm".func(c *gin.Context) {
		var login Login
		ShouldBind() selects its own binder based on the content-type of the request
		if err := c.ShouldBind(&login); err == nil {
			c.JSON(http.StatusOK, gin.H{
				"user":     login.User,
				"password": login.Password,
			})
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}
	})



	r.Run(": 9091")}Copy the code

redirect

Availability and access resource error located to the specified page

HTTP redirection

HTTP redirection is easy. Both internal and external redirection are supported.

package main
​
import (
    "github.com/gin-gonic/gin"
    "net/http"
)
​
func main(a) {
​
    r := gin.Default()
​
    r.GET("/baidu".func(context *gin.Context) {
        // HTTP redirect
        context.Redirect(http.StatusMovedPermanently, "http://www.sogo.com/")
    })
    r.Run(": 8081")}Copy the code

Route redirection

Route redirection using HandleContext:

package main
​
import (
    "github.com/gin-gonic/gin"
    "net/http"
)
​
func main(a) {
​
    r := gin.Default()
​
    r.GET("/sogo".func(context *gin.Context) {
        // Route redirection
        context.Request.URL.Path = "/baidu"
        r.HandleContext(context)
    })
​
    r.GET("/test".func(context *gin.Context) {
        context.JSON(http.StatusOK, gin.H{
            "user":     "login.User"."password": "login.Password",
        })
    })
​
    r.Run(": 8081")}Copy the code

Gin routing

Common routing

Common routes that have been used before

r.GET("/index".func(c *gin.Context){... }) r.GET("/login".func(c *gin.Context){... }) r.POST("/login".func(c *gin.Context){... })Copy the code

In addition, there is an Any method that matches all request methods as follows:

r.Any("/test".func(c *gin.Context){... })Copy the code

Add a handler for routes without a handler. By default, it returns a 404 code. The following code returns views/404.html for requests that do not match the route.

r.NoRoute(func(c *gin.Context) {
        c.HTML(http.StatusNotFound, "views/404.html".nil)})Copy the code

Routing group

Routes with a common URL prefix can be divided into a routing group. Used a pair of {} packages in the same group of routes, this is just to see clear, do you use {} packages function no difference

package main
​
import (
    "github.com/gin-gonic/gin"
    "net/http"
)
​
func main(a) {
    r := gin.Default()
    
    // Create a routing group
    userGroup := r.Group("/user")
    {
        // The first route in the routing group
        userGroup.GET("/index".func(context *gin.Context) {
            context.JSON(http.StatusOK, gin.H{
                "time" : "teime",})})// The second route in the routing group
        userGroup.POST("/login" , func(context *gin.Context) {
            context.JSON(http.StatusOK, gin.H{
                "test" : "test",
            })
        })
    }
    r.Run(": 8081")}Copy the code

Routing groups also support nesting, for example:

shopGroup := r.Group("/shop")
    {
        shopGroup.GET("/index".func(c *gin.Context){... }) shopGroup.GET("/cart".func(c *gin.Context){... }) shopGroup.POST("/checkout".func(c *gin.Context){... })// Set routines by groups
        xx := shopGroup.Group("xx")
        xx.GET("/oo".func(c *gin.Context) {...})
    }
Copy the code

Routing groups are commonly used when dividing business logic or API versions.

The 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.

A simple middleware Demo

package main
​
​
import (
    "fmt"
    "github.com/gin-gonic/gin"
    "net/http"
)
​
Middleware UE is a function
func midddleware(c *gin.Context)  {
    fmt.Println("middleware....")}func task(c *gin.Context) {
    fmt.Println("task.....")
    c.JSON(http.StatusOK, gin.H{
        "task":"sfasfsa"})},func main(a) {
    r := gin.Default()
    // Middleware executes before the task executes
    r.GET("/index", midddleware, task)
​
    r.Run(": 8081")}Copy the code

Use middleware statistics to process request times

package main
​
import (
    "fmt"
    "github.com/gin-gonic/gin"
    "net/http"
    "time"
)
​
// Statistics time-consuming middleware
func midddleware(c *gin.Context)  {
    fmt.Println("middleware....")
    start := time.Now()  // Get the present time
    c.Set("name"."LittlePrince")   // By setting the value in the request context with c.set, subsequent handlers can get the value
    c.Next()  // Invoke subsequent handlers
    // c.apport () // organizes subsequent handlers
    // Calculation time
    cost := time.Since(start)
    fmt.Printf("cost:%v \n",cost)
    fmt.Println("middleware out")}func task(c *gin.Context) {
    fmt.Println("task.....")
    c.JSON(http.StatusOK, gin.H{
        "task":"sfasfsa"})},func main(a) {
    r := gin.Default()
​
    r.GET("/index", midddleware, task)
​
    r.Run(": 8081")}Copy the code

Add middleware to a set of routes

In the GIN framework, we can add any number of middleware for each route.

Register middleware for global routing
func main(a) {
    // Create a route without any default middleware
    r := gin.Default
    // Register a global middleware
    r.Use(midddleware)
    
    r.GET("/test".func(c *gin.Context) {
        name := c.MustGet("name"). (string) // Take the value from context
        log.Println(name)
        c.JSON(http.StatusOK, gin.H{
            "message": "Hello world!",
        })
    })
    r.Run()
}
Copy the code
Register middleware for a route

See the example above using middleware statistics to process request times

Register middleware for routing groups

Method 1:

shopGroup := r.Group("/shop", StatCost())
{
    shopGroup.GET("/index".func(c *gin.Context) {...})
    ...
}
Copy the code

Method 2:

shopGroup := r.Group("/shop")
shopGroup.Use(StatCost())
{
    shopGroup.GET("/index".func(c *gin.Context) {...})
    ...
}
Copy the code

In practice, closure processing is used

// When actually using middleware, use closures to wrap one layer
func autMiddleware(doCheck bool) gin.HandlerFunc  {
    return func(c *gin.Context) {
        if doCheck{
            // Store specific logic
            // Determine whether to log in
            // if is user
            // c.next()
            // else
            // c.abort()
        }else {
            c.Next()
        }
    }
}
Copy the code

Middleware Considerations

Gin Default Middleware

Gin.Default() uses Logger and Recovery middleware by Default, where:

  • LoggerThe middleware writes the loggin.DefaultWriter, even if configuredGIN_MODE=release.
  • RecoveryMiddleware will recover anythingpanic. 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.

Goroutine is used in gin middleware

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.

Refer to the blog: www.liwenzhou.com/posts/Go/Gi…