[golang] 12, análisis del código fuente de la ginebra

inserte la descripción de la imagen aquí

github.com/gin-gonic/gin es un marco web de golang, que utiliza un árbol de diccionario para enrutar coincidencias y admite middleware. Este artículo presenta su implementación de código fuente.

uso rápido

package main

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

func main() {
    
    
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
    
    
		c.JSON(http.StatusOK, gin.H{
    
    
			"message": "pong",
		})
	})
	r.Run()
}

// curl localhost:8000/ping 则返回 PONG

El valor predeterminado es usar encoding/jsonla biblioteca, go build -tags=jsoniter .cuando github.com/json-iterator/gose usará la biblioteca.

Los ejemplos de uso oficiales se pueden encontrar en el repositorio de ejemplos de Gin .

respuesta de retorno

func Error500(ctx *gin.Context, err error) {
    
    
	ctx.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{
    
    "msg": err.Error()})
}

func Error400(ctx *gin.Context, err error) {
    
    
	ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
    
    "msg": err.Error()})
}

coincidencia de rutas

camino

package main

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

func main() {
    
    
	router := gin.Default()

	// 可以用:匹配路径
	 This handler will match /user/john or /user/ but will not match /user
	router.GET("/user/:name", func(c *gin.Context) {
    
    
		name := c.Param("name")
		c.String(http.StatusOK, "Hello %s", name)
	})

	// 可以用:匹配路径,可以用*做可选路径匹配(匹配的结果带/)
	 However, this one will match /user/john/ and also /user/john/send
	 If no other routers match /user/john, it will redirect to /user/john/
	router.GET("/user/:name/*action", func(c *gin.Context) {
    
    
		name := c.Param("name")
		action := c.Param("action")
		message := name + " is " + action
		c.String(http.StatusOK, message)
	})

	 可以用完整路径匹配
	 For each matched request Context will hold the route definition
	router.POST("/user/:name/*action", func(c *gin.Context) {
    
    
		b := c.FullPath() == "/user/:name/*action" // true
		c.String(http.StatusOK, "%t, %v", b, c.FullPath())
	})

	// 如果没有:或*	则表示路由组,可保证路由树解析优先级高于:路径匹配
	// This handler will add a new router for /user/groups.
	// Exact routes are resolved before param routes, regardless of the order they were defined.
	// Routes starting with /user/groups are never interpreted as /user/:name/... routes
	router.GET("/user/groups", func(c *gin.Context) {
    
    
		c.String(http.StatusOK, "The available groups are [...]")
	})

	router.Run(":8080")
}

Se puede *usar para hacer coincidir direcciones URL de longitud variable. Por ejemplo, el requisito es (se define una ruta /a/:nombre/d, y la dirección URL solicitada real es /a/b/c/d. ¿Cómo puede coincidir el nombre del parámetro con b/c), el ejemplo es el siguiente:
inserte la descripción de la imagen aquí

consulta

package main

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

func main() {
    
    
	router := gin.Default()

	// Query string parameters are parsed using the existing underlying request object.
	// The request responds to an url matching:  /welcome?firstname=Jane&lastname=Doe
	router.GET("/welcome", func(c *gin.Context) {
    
    
		firstname := c.DefaultQuery("firstname", "Guest")
		lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname")

		c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
	})
	router.Run(":8080")
}

Formulario de varias partes/Urlencodificado

package main

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

func main() {
    
    
	router := gin.Default()

	router.POST("/form_post", func(c *gin.Context) {
    
    
		message := c.PostForm("message")
		nick := c.DefaultPostForm("nick", "anonymous")

		c.JSON(http.StatusOK, gin.H{
    
    
			"status":  "posted",
			"message": message,
			"nick":    nick,
		})
	})
	router.Run(":8080")
}

inserte la descripción de la imagen aquí

solicitud de análisis

MultipartFrom

// ParseMultipartForm 解析 multipart/form-data 类型的 Content-Type,其将收到的文件先存储在内存中,若超限则存储在磁盘中
// ParseMultipartForm parses a request body as multipart/form-data.
// The whole request body is parsed and up to a total of maxMemory bytes of
// its file parts are stored in memory, with the remainder stored on
// disk in temporary files.
// ParseMultipartForm calls ParseForm if necessary.
// If ParseForm returns an error, ParseMultipartForm returns it but also
// continues parsing the request body.
// After one call to ParseMultipartForm, subsequent calls have no effect.
func (r *Request) ParseMultipartForm(maxMemory int64) error {
    
    
	if r.MultipartForm == multipartByReader {
    
    
		return errors.New("http: multipart handled by MultipartReader")
	}
	var parseFormErr error
	if r.Form == nil {
    
    
		// Let errors in ParseForm fall through, and just
		// return it at the end.
		parseFormErr = r.ParseForm()
	}
	if r.MultipartForm != nil {
    
    
		return nil
	}

	mr, err := r.multipartReader(false)
	if err != nil {
    
    
		return err
	}

	f, err := mr.ReadForm(maxMemory)
	if err != nil {
    
    
		return err
	}

	if r.PostForm == nil {
    
    
		r.PostForm = make(url.Values)
	}
	for k, v := range f.Value {
    
    
		r.Form[k] = append(r.Form[k], v...)
		// r.PostForm should also be populated. See Issue 9305.
		r.PostForm[k] = append(r.PostForm[k], v...)
	}

	r.MultipartForm = f

	return parseFormErr
}

La forma de pasarlo con el cartero es la siguiente:
inserte la descripción de la imagen aquí

Cuando gin analiza los parámetros, se puede multipartForm.Value["k"]recibir en la forma de recibir []string:
inserte la descripción de la imagen aquí
los parámetros analizados se definen de la siguiente manera:

// Form is a parsed multipart form.
// Its File parts are stored either in memory or on disk,
// and are accessible via the *FileHeader's Open method.
// Its Value parts are stored as strings.
// Both are keyed by field name.
type Form struct {
    
    
	Value map[string][]string
	File  map[string][]*FileHeader
}

// A FileHeader describes a file part of a multipart request.
type FileHeader struct {
    
    
	Filename string
	Header   textproto.MIMEHeader
	Size     int64

	content []byte
	tmpfile string
}

MiddleWare

El middleware y las funciones de procesamiento de gin son tipos de HandlerFunc.

// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context)

// HandlersChain defines a HandlerFunc slice.
type HandlersChain []HandlerFunc

Gin tiene varios middleware, que se implementan a través de matrices.

Supongo que te gusta

Origin blog.csdn.net/jiaoyangwm/article/details/127628726
Recomendado
Clasificación