安装 gin 框架
go get -u github.com/gin-gonic/gin
HelloWorld
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
// 创建一个默认路由
router := gin.Default()
// 绑定路由规则和函数
router.GET("/index", func(context *gin.Context) {
context.String(200, "HelloWorld !")
})
// 启动服务
router.Run(":8080")
// 第二种启动服务的方式
//http.ListenAndServe(":8080", router)
}
gin数据响应
响应 string
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
router := gin.Default()
router.GET("/str", respStr)
router.Run(":80")
}
func respStr(c *gin.Context) {
c.String(http.StatusOK, "hello world!")
}
响应 json
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
router := gin.Default()
router.GET("/str", respStr)
router.Run(":80")
}
func respJson(c *gin.Context) {
//1. json响应结构体
type User struct {
Username string `json:"username"`
Age int `json:"age"`
Password string `json:"-"` // "-"表示序列化的时候跳过该字段
}
user := User{
Username: "Hale",
Age: 20,
Password: "qwe23",
}
c.JSON(http.StatusOK, user)
//2. json 响应 map
userMap := map[string]string{
"username": "TT",
"age": "23",
}
c.JSON(http.StatusOK, userMap)
//3. 直接响应 json
c.JSON(http.StatusOK, gin.H{"username": "TT", "age": 14})
}
响应 xml
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
router := gin.Default()
router.GET("/xml", respXml)
router.Run(":80")
}
func respXml(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"username": "TT", "age": 14})
}
重定向
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
router := gin.Default()
router.GET("/redirect", respRedirect)
router.Run(":80")
}
func respRedirect(c *gin.Context) {
c.Redirect(http.StatusFound, "https://baidu.com")
}
gin 请求参数
获取查询参数
package main
import (
"github.com/gin-gonic/gin"
)
// 获取查询传参
func _query(c *gin.Context) {
user := c.Query("user")
//user, ok := c.GetQuery("user")
c.QueryArray("user") // 多个相同查询参数的切片
c.String(200, user)
}
func main() {
router := gin.Default()
router.GET("/query", _query)
router.Run(":80")
}
// http://127.0.0.1
获取动态参数
package main
import (
"github.com/gin-gonic/gin"
)
// 获取查询传参
func _param(c *gin.Context) {
param := c.Param("user_id")
c.String(200, param)
}
func main() {
router := gin.Default()
router.GET("/param/:user_id/", _param)
router.GET("/param/:user_id/:age/", _param)
router.Run(":80")
}
// http://127.0.0.1/param/xxx
表单参数 PostForm
package main
import (
"github.com/gin-gonic/gin"
)
// 获取查询传参
func _form(c *gin.Context) {
param := c.PostForm("name")
params := c.PostFormArray("name")
form := c.DefaultPostForm("user", "Jelo") // 如果没传就指定默认值
c.String(200, param)
}
func main() {
router := gin.Default()
router.POST("/form", _form)
router.Run(":80")
}
原始参数 GetRawData
package main
import (
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
)
// 解析 json 数据的封装
func bindJson(c *gin.Context, obj any) (err error) {
body, _ := c.GetRawData()
ContentType := c.GetHeader("Content-Type")
switch ContentType {
case "application/json":
err = json.Unmarshal(body, &obj)
if err != nil {
return err
}
}
return nil
}
// 获取原始参数
func _raw(c *gin.Context) {
type User struct {
Name string `json:"name"`
Age string `json:"age"`
}
var user User
err := bindJson(c, &user)
if err != nil {
fmt.Print(err)
}
c.JSON(200, user)
}
func main() {
router := gin.Default()
router.POST("/raw", _raw)
router.Run(":80")
}
四大请求方式
package main
import (
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
)
type Article struct {
Title string `json:"title"`
Content string `json:"content"`
}
type Response struct {
Code int `json:"code"`
Data any `json:"data"`
Msg string `json:"msg"`
}
func bindToJson(c *gin.Context, obj any) (err error) {
body, _ := c.GetRawData()
ContentType := c.GetHeader("Content-Type")
switch ContentType {
case "application/json":
err = json.Unmarshal(body, &obj)
if err != nil {
return err
}
}
return nil
}
func getList(c *gin.Context) {
data := []Article{
{Title: "Test1", Content: "xxxxxx"},
{Title: "Test2", Content: "xxxxxx"},
}
c.JSON(200, Response{0, data, "succ"})
}
func getDetail(c *gin.Context) {
// 从 param 中获取 id
c.Param("id")
article := Article{
Title: "Test1", Content: "xxxxxx",
}
c.JSON(200, Response{0, article, "succ"})
}
func create(c *gin.Context) {
// 接收前端传递来的数据
var article Article
err := bindToJson(c, &article)
if err != nil {
fmt.Print(err)
}
c.JSON(200, Response{0, article, "succ"})
}
func update(c *gin.Context) {
// 从 param 中获取 id
c.Param("id")
var article Article
err := bindToJson(c, &article)
if err != nil {
fmt.Print(err)
}
c.JSON(200, Response{0, article, "succ"})
}
func delete(c *gin.Context) {
c.Param("id")
// 库里面删除
c.JSON(200, Response{0, map[string]string{}, "succ"})
}
func main() {
router := gin.Default()
router.GET("/articles", getList)
router.GET("/articles/:id/", getDetail)
router.POST("/articles", create)
router.PUT("/articles/:id/", update)
router.DELETE("/articles/:id/", delete)
router.Run(":80")
}
请求头相关
请求头参数获取
package main
import (
"github.com/gin-gonic/gin"
"strings"
)
func main() {
engine := gin.Default()
engine.GET("/", func(c *gin.Context) {
// 首字母不区分大小写
c.GetHeader("User-Agent")
c.JSON(200, gin.H{"msg": "succ"})
// 自定义请求头可以按照如下获取
c.Request.Header.Get("token")
})
// demo1 反爬虫
engine.GET("/index", func(c *gin.Context) {
userAgent := c.GetHeader("User-Agent")
// 正则或者字符串包含匹配
if strings.Contains(userAgent, "python") {
//todo
}
})
engine.Run(":80")
}
响应头相关
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
engine := gin.Default()
engine.GET("/", func(c *gin.Context) {
// 设置响应头
c.Header("Token", "asfwx13ssc23")
c.JSON(200, gin.H{"msg": "succ"})
})
engine.Run(":80")
}
bind 绑定参数
gin 中的 bind 可以很方便的将前端穿都来的数据与结构体进行参数绑定
ShouldBindJSON
绑定请求 body 里面的参数到结构体
package main
import (
"github.com/gin-gonic/gin"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Sex string `json:"sex"`
}
func main() {
router := gin.Default()
router.POST("/", func(c *gin.Context) {
var userInfo User
// 这里的 bind 会自带参数校验功能
err := c.ShouldBindJSON(&userInfo)
if err != nil {
c.JSON(200, "userInfo failed")
return
}
c.JSON(200, userInfo)
})
router.Run(":80")
}
ShouldBindQuery
绑定请求查询参数(params)的参数到结构体
tag 对应 form
package main
import (
"github.com/gin-gonic/gin"
)
type User struct {
Name string `json:"name" form:"name"`
Age int `json:"age" form:"age"`
Sex string `json:"sex" form:"sex"`
}
func main() {
router := gin.Default()
router.POST("/", func(c *gin.Context) {
var userInfo User
// 这里的 bind 会自带参数校验功能
err := c.ShouldBindQuery(&userInfo)
if err != nil {
c.JSON(200, "userInfo failed")
return
}
c.JSON(200, userInfo)
})
router.Run(":80")
}
ShouldBindUri
绑定 url 中的参数到结构体,用法参考ShouldBindQuery
ShouldBind
会根据请求头中的 content-type 去自动绑定
form-data 的参数也用这个,tag 用 form
func main() {
router := gin.Default()
router.POST("/form", func(c *gin.Context) {
var userInfo User
// 这里的 bind 会自带参数校验功能
err := c.ShouldBind(&userInfo)
if err != nil {
c.JSON(200, "userInfo failed")
return
}
c.JSON(200, userInfo)
})
router.Run(":80")
}
bind常用验证器
package main
import (
"github.com/gin-gonic/gin"
)
type User struct {
Name string `json:"name" binding:"required"`
Age int `json:"age" binding:"lt=30,gt=18"`
Password string `json:"password"`
RePassword string `json:"re_password" binding:"eqfield=Password"`
Hobby []string `json:"hobby" binding:"required,dive,startswith=xx"`
}
func main() {
router := gin.Default()
router.POST("/", func(c *gin.Context) {
var user User
err := c.ShouldBindJSON(&user)
if err != nil {
c.JSON(200, gin.H{"msg": err.Error()})
} else {
c.JSON(200, gin.H{"msg": user})
}
})
router.Run(":80")
}
/*
required: 必须字段
min,max:最大最小验证
len 长度验证,例如 bingding:"len=6"
eq,ne,gt,gte,lt,lte
eqfield 等于其它字段的值,例如 RePassword string `binding:"eqfield=Password"`
nefield 不等于其它字段的值
- 忽略猴哥字段,例如:binding:"-"
*/
其它内置验证器
/*
枚举
oneof=red green
字符串
contains=harry
excludes // 不包含
startswith
endswith
数组
dive 例如 Hobby []string `json:"hobby" binding:"required,dive,startswith=xx"`
网络验证
ip,ipv4,ipv6,uri,url
*/
自定义错误信息
package main
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"reflect"
)
type User struct {
Name string `json:"name" binding:"required" msg:"用户名必须"`
Age int `json:"age" binding:"lt=30,gt=18"`
Sex string `json:"sex" binding:"oneof=man women"`
Hobby []string `json:"hobby" binding:"required,dive,startswith=xx"`
}
func GetValidMsg(obj any, err error) string {
getObj := reflect.TypeOf(obj)
if err != nil {
// 将 err 接口断言为具体类型
if errs, ok := err.(validator.ValidationErrors); ok {
for _, e := range errs {
// 根据报错字段名获取结构体的具体字段
if f, exists := getObj.Elem().FieldByName(e.Field()); exists {
msg := f.Tag.Get("msg")
return msg
}
}
}
}
return err.Error()
}
func main() {
router := gin.Default()
router.POST("/", func(c *gin.Context) {
var user User
err := c.ShouldBindJSON(&user)
if err != nil {
c.JSON(200, gin.H{"msg": GetValidMsg(&user, err)})
return
}
c.JSON(200, gin.H{"data": user})
})
router.Run(":80")
}
自定义验证器
package main
import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
)
type User struct {
Name string `json:"name" binding:"required,sign"`
Age int `json:"age" binding:"lt=30,gt=18"`
}
func main() {
router := gin.Default()
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
v.RegisterValidation("sign", signValid)
}
router.POST("/", func(c *gin.Context) {
var user User
err := c.ShouldBindJSON(&user)
if err != nil {
c.JSON(200, gin.H{"msg": err.Error()})
return
}
c.JSON(200, gin.H{"data": user})
})
router.Run(":80")
}
func signValid(fl validator.FieldLevel) bool {
var nameList = []string{"asa", "sdfa", "csd"}
for _, nameStr := range nameList {
name := fl.Field().Interface().(string)
if name == nameStr {
return false
}
}
return true
}