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…
GET
To get resourcesPOST
To create a new resourcePUT
Used to update resourcesDELETE
Used 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:
- If it is
GET
Request, use onlyForm
Binding engine (query
). - If it is
POST
Request, check firstcontent-type
Whether it isJSON
或XML
And 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:
Logger
The middleware writes the loggin.DefaultWriter
, even if configuredGIN_MODE=release
.Recovery
Middleware 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…