Gin基本使用

本文详细介绍了Gin框架的使用,包括安装、创建基本的HTTP服务、处理各种HTTP请求方法、静态文件服务、URL参数、泛绑定、获取请求参数(GET、POST、body内容、bind参数)、结构体验证及自定义验证规则,以及多语言验证错误提示。此外,还讲解了Gin的中间件机制,如内置的日志和恢复中间件,并展示了如何自定义中间件。通过实例代码,深入理解Gin在Web开发中的强大功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Gin框架使用
*基于httprouter开发的web框架
*提供Martini风格的API,但比Martini要快40倍
*非常轻量级,使用起来非常简洁
Gin框架安装与使用
*安装:go get -u github.com/gin-gonic/gin
*import"github.com/gin-gonic/gin"
第一个Gin程序

package main

import "github.com/gin-gonic/gin"

func main(){
r := gin.Default()//创建一个默认的路由引擎
r.GET("/ping",func(c *gin.Context){//创建测试的路由
//GET:请求方式    /ping:请求的路径
//当客户端以GET方法请求/ping路径时,会执行后面的匿名函数
//c.JSON:返回JSON格式的数据
    c.JSON(200,gin.H{
   "message":"pong",
})
   })
   //启动HTTP服务,默认在0.0.0.0:8200启动服务
   r.Run(":8200")
}

1.首先,我们使用了gin.Default()生成了一个实例,这个实例即WSGI应用程序(Web服务器网关接口)。
2.接下来,我们使用了r.GET("/",…)声明了一个路由,告诉Gin什么样的URL(在www上,每一信息资源都有统一的且在网上唯一的地址,该地址就叫URL)能触发传入的函数,这个函数返回我们想要显示在用户浏览器中的信息。
3.最后用r.Run()函数来让应用运行在本地服务器上,默认监听端口是8200,可以传入参数设置端口,例如r.Run(":9999")即运行在9999端口。
4.然后使用浏览器打开127.0.0.1:8200/ping就能看到一串JSON字符串
请求路由-多种请求

package main

import "github.com/gin-gonic/gin"

func main(){
	r := gin.Default()
	r.GET("/get",func(c *gin.Context){
		c.String(200,"get")
	})
	r.POST("/post",func(c *gin.Context){
		c.String(200,"post")
	})
	r.Handle("DELETE","/delete",
		func(c *gin.Context){
			c.String(200,"delete")
		})
	r.Any("/any",func(c *gin.Context){
		c.String(200,"any")
	})
	r.Run()
}

请求路由-静态文件夹

package main

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

func main(){
	r := gin.Default()
    r.Static("/assets","./assets")
	//先设置路由,再设置相对文件夹
	//另外一种写法
    r.StaticFS("/static",http.Dir("static"))
	//先设置路由,再设置资源
	//设置单个静态文件
	r.StaticFile("/favicon.ico",
		"./favicon.ico")
	//设置路由,设置资源
	r.Run()//启动服务器
}

请求路由-参数作为url

package main

import "github.com/gin-gonic/gin"

func main(){
	r := gin.Default()
	r.GET("/:name/:id",func(c *gin.Context){
		c.JSON(200,gin.H{
			"name":c.Param("name"),
			"id":c.Param("id"),
		})
	})
	r.Run()
}

请求路由-泛绑定

package main

import "github.com/gin-gonic/gin"

func main(){
	r := gin.Default()
	r.GET("/user/*action",
		func(c *gin.Context){
			c.String(200,"hello world")
		})
	r.Run()
}

获取请求参数-获取GET参数

package main

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

func main(){
	r := gin.Default()
	r.GET("/test",func(c *gin.Context){
		firstName := c.Query("first_name")
		lastName := c.DefaultQuery("last_name",
		"last_default_name")
		c.String(http.StatusOK,"%s,%s",
			firstName,lastName)
	})
	r.Run(":8080")
}

获取请求参数-获取body内容

package main

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

func main(){
	r := gin.Default()
	r.POST("/test",func(c *gin.Context){
		bodyByts,err := ioutil.ReadAll(c.Request.Body)
		if err != nil{
			c.String(http.StatusBadRequest,err.Error())
			c.Abort()
		}
		c.String(http.StatusOK,string(bodyByts))
	})
	r.Run()
}

获取请求参数-获取bind参数

package main

import (
	"github.com/gin-gonic/gin"
	"time"
)

type Person struct{
	Name string   `form:"name"`
	Address string    `form:"address"`
	Birthday time.Time   `form:"birthday"`
}
func main(){
	r := gin.Default()
    r.GET("/testing",testing)
	r.POST("/testing",testing)
	r.Run()
}

func testing(c *gin.Context){
    var person Person
    if err := c.ShouldBind(&person);err==nil{
    	c.String(200,"%v",person)
	}else{
		c.String(200,"person bind error:%v",err)
	}
}

验证请求参数-结构体验证

package main

import "github.com/gin-gonic/gin"

type Person struct{
	Age int    `form:"age" binding:"required,gt=10"`
	Name string    `form:"name" binding:"required"`
	Address string  `form:"address" binding:"required"`
}
func main(){
     r := gin.Default()
     r.GET("/testing",func(c *gin.Context){
         var person Person
         if err := c.ShouldBind(&person);err != nil{
         	c.String(500,"%v",err)
		 }
		 c.String(200,"%v",person)
	 })
     r.Run()
}

验证请求参数-自定义验证规则

package main

import (
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"net/http"
	"time"
)

type Booking struct{
	CheckIn time.Time `form:"check_in" validate:"required,bookableDate" time_format:"2006-01-02"`
	CheckOut time.Time `form:"check_out" validate:"required,gtfield=CheckIn" time_format:"2006-01-02`
}
func main(){
	r := gin.Default()
	validate := validator.New()
	validate.RegisterValidation("bookableDate",bookableDate)
	r.GET("/bookable",func(c *gin.Context){
		var book Booking
		if err := c.ShouldBind(&book);err != nil{
			c.JSON(http.StatusInterServerError,gin.H{
				"error":err.Error(),
			})
			c.Abort()
			return
		}
		if err := validate.Struct(book);err != nil{
			c.JSON(http.StatusInternalServerError,gin.H{
				"error":err.Error(),
			})
			c.Abort()
			return
		}
		c.JSON(http.StatusOK,gin.H{
			"message":"OK",
			"booking":book,
		})
	})
	r.Run()
}

func bookableDate(fl validator.FieldLevel)bool{
	if date,ok := fl.Field().Interface().(time.Time);ok{
		today := time.Now()
		if date.Unix() > today.Unix(){
			return true
		}
	}
	return false
}

验证请求参数-多语言翻译验证

package main

import (
	"github.com/gin-gonic/gin"
	en2 "github.com/go-playground/locales/en"
	zh2 "github.com/go-playground/locales/zh"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	en_translations "gopkg.in/go-playground/validator.v9/translations/en"
	zh_translations "gopkg.in/go-playground/validator.v9/translations/zh"
)

type people struct{
	Age int `form:"age" validate:"required,gt=10"`
	Name string `form:"name" validate:"required"`
	Address string `form:"address" validate:"required"`
}
var(
	Uni *ut.UniversalTranslator
	Validate *validator.Validate
)
//验证信息多语言化
func main(){
    Validate = validator.New()//创建一个验证器
    zh := zh2.New()
    en := en2.New()
    Uni = ut.New(zh,en)//创建翻译器,翻译器里有可支持的语言
    r := gin.Default()
    r.GET("/testing",func(c *gin.Context){
    	locale := c.DefaultQuery("locale",
    		"zh")
    	trans,_ := Uni.GetTranslator("locale")
    	switch locale{
		case "zh":
			zh_translations.RegisterDefaultTranslations(Validate,trans)
		case "en":
			en_translations.RegisterDefaultTranslations(Validate,trans)
		default:
			zh_translations.RegisterDefaultTranslations(Validate,trans)
		}
		var person people
    	if err := c.ShouldBind(&person);err != nil{//结构绑定
    		c.String(500,"%v",err)
    		c.Abort()
    		return
		}
		if err := Validate.Struct(person);err != nil{
			errs := err.(validator.ValidationErrors)
			sliceErrs := []string{}
			for _,e := range errs{
				sliceErrs=append(sliceErrs,e.Translate(trans))
			}
            c.String(500,"%v",sliceErrs)
			c.Abort()
			return
		}
		c.String(200,"%v",person)
	})
    r.Run()
}

Gin中间件
Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等
中间件-使用

package main

import "github.com/gin-gonic/gin"

func main(){
	r := gin.New()//这次用new来实现
    r.Use(gin.Logger())//设置中间件
    r.GET("/test",func(c *gin.Context){
    	name := c.DefaultQuery("name","default_name")
    	c.String(200,"%s",name)
	})
	r.Run()
}

那么,想把错误打印到文件应该怎么办呢?、

package main

import (
	"github.com/gin-gonic/gin"
	"io"
	"os"
)

func main(){
	f,_ := os.Create("gin.log")
	gin.DefaultWriter = io.MultiWriter(f)
	gin.DefaultErrorWriter = io.MultiWriter(f)
	r := gin.New()//这次用new来实现
    r.Use(gin.Logger())//设置中间件
    r.GET("/test",func(c *gin.Context){
    	name := c.DefaultQuery("name","default_name")
    	c.String(200,"%s",name)
	})
	r.Run()
}

gin.Recovery的作用

package main

import (
	"github.com/gin-gonic/gin"
	"io"
	"os"
)

func main(){
	f,_ := os.Create("gin.log")
	gin.DefaultWriter = io.MultiWriter(f)
	gin.DefaultErrorWriter = io.MultiWriter(f)
	r := gin.New()//这次用new来实现
    r.Use(gin.Logger(),gin.Recovery())//设置中间件
    r.GET("/test",func(c *gin.Context){
    	name := c.DefaultQuery("name","default_name")
    	panic("test panic")//加上这个程序不至于报错
    	c.String(200,"%s",name)
	})
	r.Run()
}

中间件-自定义中间件

Gin框架中使用JWT(JSON Web Token)可以实现份验证和授权功能。JWT是一种用于在网络应用间传递信息的安全方法,它由三部分组成:header、payload和signature[^1]。 下面是在Gin框架中使用JWT的示例代码[^2]: 1. 导入所需的包: ```go import ( "github.com/gin-gonic/gin" "github.com/dgrijalva/jwt-go" ) ``` 2. 定义JWT的密钥: ```go var jwtKey = []byte("your_secret_key") ``` 3. 创建一个JWT的Claims结构体,用于存储用户的信息: ```go type Claims struct { Username string `json:"username"` jwt.StandardClaims } ``` 4. 创建一个处理登录请求的路由: ```go func login(c *gin.Context) { var loginData LoginData if err := c.ShouldBindJSON(&loginData); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"}) return } // 验证用户名和密码 if loginData.Username == "admin" && loginData.Password == "password" { // 创建JWT的Claims claims := &Claims{ Username: loginData.Username, StandardClaims: jwt.StandardClaims{ ExpiresAt: time.Now().Add(time.Hour * 24).Unix(), // 设置过期时间 }, } // 创建JWT token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) tokenString, err := token.SignedString(jwtKey) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"}) return } // 返回JWT给客户端 c.JSON(http.StatusOK, gin.H{"token": tokenString}) } else { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"}) } } ``` 5. 创建一个需要身份验证的路由: ```go func protectedRoute(c *gin.Context) { // 从请求头中获取JWT authHeader := c.GetHeader("Authorization") if authHeader == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "Missing authorization header"}) return } // 解析JWT tokenString := authHeader[7:] // 去除Bearer前缀 claims := &Claims{} token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) { return jwtKey, nil }) if err != nil { if err == jwt.ErrSignatureInvalid { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token signature"}) return } c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid token"}) return } if !token.Valid { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) return } // 验证通过,继续处理请求 c.JSON(http.StatusOK, gin.H{"message": "Protected route"}) } ``` 6. 在路由中注册处理函数: ```go func main() { r := gin.Default() r.POST("/login", login) r.GET("/protected", protectedRoute) r.Run(":8080") } ``` 以上代码演示了在Gin框架中使用JWT进行身份验证和授权的基本流程。用户可以通过发送登录请求获取JWT,然后在需要身份验证的路由中将JWT放入请求头中进行验证。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李元芳芳芳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值