参数校验(一)
uuid包:https://github.com/satori/go.uuid
因为作者更改了参数限制,导致会出问题 → 问题解决
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
uuid "github.com/gofrs/uuid"
"net/http"
"unicode/utf8"
)
type UserInfo struct {
Id string `validate:"uuid" json:"id"` // UUID 类型
Name string `validate:"checkName" json:"name"` // 自定义校验
Age uint8 `validate:"min=0,max=130" json:"age"` // 大于0小于130
}
var validate *validator.Validate
// 校验初始化
func init() {
validate = validator.New() // 初始化校验示例
validate.RegisterValidation("checkName", checkNameFunc) // 自定义校验方法
}
func checkNameFunc(fl validator.FieldLevel) bool {
count := utf8.RuneCountInString(fl.Field().String()) // 获取 Name 的字符串表示,并计算 Unicode 字符的数量
if count >= 2 && count <= 12 {
return true
}
return false
}
func main() {
uuid.Must(uuid.NewV4()) // 由 uuid包 生成 uuid
r := gin.Default()
var user UserInfo
r.POST("/validate", func(context *gin.Context) {
err := context.Bind(&user)
if err != nil {
context.JSON(http.StatusBadRequest, "请求参数错误")
return
}
err = validate.Struct(user)
if err != nil {
for _, e := range err.(validator.ValidationErrors) {
fmt.Println("错误的字段:", e.Field())
fmt.Println("错误的值:", e.Value())
fmt.Println("错误的tag:", e.Tag())
}
context.JSON(http.StatusBadRequest, "数据校验失败")
return
}
context.JSON(http.StatusOK, "数据校验成功")
})
r.Run(":9090")
}
参数校验(二)
validator包:https://github.com/go-playground/validator
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"net/http"
)
type ValUser struct {
Name string `validate:"required" json:"name"`
Age uint8 `validate:"gte=0,lte=130" json:"age"`
Email string `validate:"required,email" json:"email"`
// 切片数据类型
Address []ValAddress `validate:"dive" json:"address"`
}
type ValAddress struct {
Province string `validate:"required" json:"province"`
City string `validate:"required" json:"city"`
Phone string `validate:"numeric,len=11" json:"phone"`
}
var validate *validator.Validate
func init() {
validate = validator.New() // 初始化
}
func main() {
r := gin.Default()
var user ValUser
r.POST("/validate", func(context *gin.Context) {
//testData(context)
err := context.Bind(&user)
if err != nil {
context.JSON(http.StatusBadRequest, "参数错误,绑定失败")
return
}
// 参数校验
if validateUser(user) {
context.JSON(http.StatusOK, "数据校验成功")
return
}
context.JSON(http.StatusBadRequest, "校验失败")
return
})
r.Run(":9090")
}
//func testData(context *gin.Context) {
// address := ValAddress{
// Province: "浙江省",
// City: "杭州市",
// Phone: "13575121689",
// }
// user := ValUser{
// Name: "张三",
// Age: 15,
// Email: "1993036922@qq.com",
// Address: []ValAddress{address},
// }
// context.JSON(http.StatusOK, user)
//}
func validateUser(u ValUser) bool {
err := validate.Struct(u)
if err != nil {
for _, e := range err.(validator.ValidationErrors) {
fmt.Println("错误的字段:", e.Field())
fmt.Println("错误的值:", e.Value())
fmt.Println("错误的tag:", e.Tag())
}
return false
}
return true
}
swagger
swagger地址:https://github.com/swaggo/gin-swagger
引入步骤
- 下载swag及相关包
- go get -u github.com/swaggo/swag/cmd/swag
- go get -u github.com/swaggo/gin-swagger
- go get -u github.com/swaggo/files
- 实现 Api 代码
- 编写注释:参考https://github.com/swaggo/swag/blob/master/README.md#declarative-comments-format
- 在代码中使用 swagger 中间件
- 引入docs:如我的引入为 _ "2-golang/docs",_ 表示不为包赋名
- 执行终端命令:swag init
如果出现 swag 不是命令,无法识别,则先执行: go install github.com/swaggo/swag/cmd/swag@latest
ps:文件名必须叫 main
go
package main
import (
_ "2-golang/docs"
"fmt"
"github.com/gin-gonic/gin"
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
"net/http"
)
type User struct {
UserName string `json:"user_name"`
Password string `json:"password"`
}
type Response struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data string `json:"data"`
}
func main() {
r := gin.Default()
// 使用 swagger 中间件
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
r.GET("/login", login)
r.POST("/register", register)
r.Run(":9090")
}
// @Tags 注册接口
// @Summary 注册
// @Description register
// @Accept json
// @Produce json
// @Param username formData string true "用户名"
// @Param password formData string true "密码"
// @Success 200 {string} json "{"code": 200, "data":"{"name":"username","password":"password"}","msg":"OK"}"
// @Router /register [post]
func register(context *gin.Context) {
var user User
// get 使用的是 query,post 使用的是 formData,而 Bind 只能绑定 query
// err := context.Bind(&user)
err := context.BindQuery(&user)
if err != nil {
context.JSON(http.StatusBadRequest, "数据错误")
return
}
res := Response{
Code: http.StatusOK,
Msg: "注册成功",
Data: "OK",
}
context.JSON(http.StatusOK, res)
}
// @Tags 登录接口
// @Summary 登录
// @Description login
// @Accept json
// @Produce json
// @Param username query string true "用户名"
// @Param password query string false "密码"
// @Success 200 {string} json "{"code": 200, "data":"{"name":"username","password":"password"}","msg":"OK"}"
// @Router /login [get]
func login(context *gin.Context) {
userName := context.Query("name")
pwd := context.Query("pwd")
fmt.Println(userName, pwd)
res := Response{}
res.Code = http.StatusOK
res.Msg = "登陆成功"
res.Data = "OK"
context.JSON(http.StatusOK, res)
}
gin框架cookie
go
package main
import (
"encoding/hex"
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
var cookieName string
var cookieValue string
func main() {
r := gin.Default()
r.Use(cookieAuth())
r.GET("/cookie", func(context *gin.Context) {
name := context.Query("name")
if len(name) <= 0 {
context.JSON(http.StatusOK, "数据错误")
return
}
cookieName = "cookie_" + name
cookieValue = hex.EncodeToString([]byte(cookieName + "value"))
val, _ := context.Cookie(cookieName)
if val == "" {
context.String(http.StatusOK, "Cookie已经下发,下次登录有效", cookieName)
return
}
context.String(http.StatusOK, "验证成功,cookie值为:%s", val)
})
r.Run(":9090")
}
func cookieAuth() gin.HandlerFunc {
return func(context *gin.Context) {
val, _ := context.Cookie(cookieName)
if val == "" {
context.SetCookie(cookieName, cookieValue, 3600, "/", "localhost", true, true)
fmt.Println("cookie已经保存完成!")
}
}
}
gin框架session
go
package main
import (
"net/http"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// 加入 session 中间件
store := cookie.NewStore([]byte("session_secret")) // 创建基于cookie的session存储
r.Use(sessions.Sessions("mySession", store)) // 使用session中间件,并指定session名称和存储方式
r.GET("/session", func(context *gin.Context) {
name := context.Query("name")
if len(name) <= 0 {
context.JSON(http.StatusOK, "数据错误")
return
}
sessionName := "session_" + name // 构造session名称
sessionValue := "session_value_" + name // 构造session值
session := sessions.Default(context) // 获取默认的session实例
sessionData := session.Get(sessionName)
if sessionData != sessionValue { // 如果session中不存在对应值,则为首次访问
session.Set(sessionName, sessionValue) // 设置 session
session.Save() // 保存 session
context.JSON(http.StatusOK, "首次访问,session已保存:"+sessionValue)
return
}
context.JSON(http.StatusOK, "访问成功,您的session是:"+sessionData.(string))
})
r.Run(":9090") // 启动HTTP服务器,监听9090端口
}
gin框架Https
- 申请证书并下载证书:https://keymanager.org/
go
package main
import (
"github.com/gin-gonic/gin"
"github.com/unrolled/secure"
"net/http"
)
// HttpRes 结构体用于定义HTTP响应格式
type HttpRes struct {
Code int `json:"code"` // 响应状态码
Result string `json:"result"` // 响应结果消息
}
func main() {
r := gin.Default() // 创建默认的gin路由引擎
// 使用HTTPS处理程序中间件
r.Use(httpsHandler())
// 定义GET路由"/https_test"
r.GET("/https_test", func(context *gin.Context) {
// 返回JSON格式的成功消息
context.JSON(http.StatusOK, HttpRes{
Code: http.StatusOK,
Result: "测试成功",
})
})
path := "D:/2-golang/CA/" // 证书路径
r.RunTLS(":9090", path+"ca.crt", path+"ca.key") // 使用TLS在9090端口运行服务器
}
// httpsHandler 返回一个处理HTTPS请求的中间件函数
func httpsHandler() gin.HandlerFunc {
return func(context *gin.Context) {
// 创建secure中间件实例
secureMiddleware := secure.New(secure.Options{
SSLRedirect: true, // 强制SSL重定向
STSSeconds: 1536000,
STSIncludeSubdomains: true,
STSPreload: true,
FrameDeny: true,
ContentTypeNosniff: true,
BrowserXssFilter: true,
})
// 处理HTTPS请求
err := secureMiddleware.Process(context.Writer, context.Request)
if err != nil {
// 如果出现错误,返回数据不安全的响应
context.AbortWithStatusJSON(http.StatusBadRequest, "数据不安全")
return
}
if status := context.Writer.Status(); status > 300 && status < 399 {
// 如果响应状态码是重定向类型,则终止请求
context.Abort()
return
}
context.Next() // 继续处理下一个中间件或路由处理函数
}
}