参数校验(一)
uuid包:https://github.com/satori/go.uuid
因为作者更改了参数限制,导致会出问题 → 问题解决
package mainimport ("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包 生成 uuidr := gin.Default()var user UserInfor.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
package mainimport ("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.Validatefunc init() {validate = validator.New() // 初始化
}func main() {r := gin.Default()var user ValUserr.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
package mainimport (_ "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.StatusOKres.Msg = "登陆成功"res.Data = "OK"context.JSON(http.StatusOK, res)
}
gin框架cookie
package mainimport ("encoding/hex""fmt""github.com/gin-gonic/gin""net/http"
)var cookieName string
var cookieValue stringfunc 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_" + namecookieValue = 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
package mainimport ("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) // 设置 sessionsession.Save() // 保存 sessioncontext.JSON(http.StatusOK, "首次访问,session已保存:"+sessionValue)return}context.JSON(http.StatusOK, "访问成功,您的session是:"+sessionData.(string))})r.Run(":9090") // 启动HTTP服务器,监听9090端口
}
gin框架Https
- 申请证书并下载证书:https://keymanager.org/
package mainimport ("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() // 继续处理下一个中间件或路由处理函数}
}