Gin入门
- Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确,具有快速灵活,容错方便等特点
- 对于Golang而言,web框架的依赖要远比Python,Java之类要小,自身的net/http足够简单,性能也非常不错
- 借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范.
安装
要安装Gin 软件包,需要先安装GO并设置Go工作区.
首先需要安装GO,然后可以使用GO命令安装Gin.在go.mod同级目录执行以下命令.
go get -u github.com/gin-gonic/gin
Gin入门与源码
一共需要3步.
创建路由
路由绑定
启动监听
func main() {
// 1. 创建路由
r := gin.Default()
// 2. 路由绑定
r.GET("/", func(c *gin.Context) {
c.String(200, "ok")
})
// 3. 启动监听
fmt.Println("http://192.168.31.1:8080")
r.Run(":8080")
}
gin核心概念
- Engine 容器对象,整个框架基础
- Engine.trees 负责存储路由和handle方法的映射,采用类似字典树的结构
- Engine.RouterGroup 其中Handlers存储着所有中间件
- Context上下文对象,负责处理请求和回应,其中handlers是存储处理请求时中间件和处理方法的.
gin 路由
无参路由
不传递任何数据
func main() {
// 1. 定义路由
r := gin.Default()
// 2. 定义路由
r.GET("/hello", HelloHandler)
// 3. 启动监听
fmt.Println("http://192.168.31.1:8080/hello")
r.Run(":8080")
}
func HelloHandler(c *gin.Context) {
c.String(200, "hello world")
}
- gin 框架中采用的路由库是基于httprouter做的
- 因为虽然net/http这个包里有着默认路由,但是仍存在着不足,所以使用httprouter
- httprouter 是一个高性能、可扩展的HTTP路由,上面我们列举的net/http默认路由的不足,都被httprouter 实现
Api传参
func main() {
// 1. 定义
r := gin.Default()
r.GET("/book/:id", GetBookHandler)
fmt.Println("http://localhost:8080/")
r.Run(":8080")
}
func GetBookHandler(c *gin.Context) {
bookID := c.Param("id")
fmt.Println(bookID, "------->")
book := "你找的书:" + bookID + "已经找到\n"
c.String(200, book)
}
Url传参
-
URL参数可以通过DefaultQuery()或Query()方法获取
-
DefaultQuery()若参数不存在,返回默认值,Query()若不存在,返回空串
func main() { r := gin.Default() r.GET("/user", UrlGetHandler) fmt.Println("http://192.168.31.1:8080/") r.Run(":8080") } func UrlGetHandler(c *gin.Context) { username := c.Query("username") password := c.Query("password") output := "你输入的用户名是:" + username + " 密码是:" + password c.String(200, output) }
设置默认值
func main() {
r := gin.Default()
r.GET("/user", UrlGetHandler)
fmt.Println("http://192.168.31.1:8080/")
r.Run(":8080")
}
func UrlGetHandler(c *gin.Context) {
username := c.Query("username")
//password := c.Query("password")
password := c.DefaultQuery("password", "你没有输入密码")
output := "你输入的用户名是:" + username + " 密码是:" + password
c.String(200, output)
}
如果这里没有传值就会用默认值替代 如果传入值,那么就用传入的值.
shouldBind
用来解析Post请求中复杂的Json数据
func main() {
r := gin.Default()
r.POST("/user/login", LoginHandler)
r.Run(":8080")
}
type Login struct {
Username string `json:"username"`
Password string `json:"password"`
}
func LoginHandler(c *gin.Context) {
var login Login
if err := c.ShouldBind(&login); err != nil {
c.String(400, "err")
return
}
Code := login.Username + " Login Succeeded!"
c.String(200, Code)
}
也可以将某个参数设为必须
func main() {
r := gin.Default()
r.POST("/user/login", LoginHandler)
r.Run(":8080")
}
type Login struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
func LoginHandler(c *gin.Context) {
var login Login
if err := c.ShouldBind(&login); err != nil {
fmt.Println(err)
c.String(400, "err")
return
}
Code := login.Username + " Login Succeeded!"
c.String(200, Code)
}
当没有传该参数时就会报错
数据返回Response
String字符串返回
func main() {
r := gin.Default()
r.GET("/response", ResponseHandler)
r.Run(":8080")
}
func ResponseHandler(c *gin.Context) {
msg := "success response"
c.String(200, msg)
}
返回Json数据
func main() {
r := gin.Default()
r.GET("/response", JsonHandler)
r.Run(":8080")
}
func JsonHandler(c *gin.Context) {
type Data struct {
Msg string `json:"msg"`
Code int `json:"code"`
}
d := Data{
Msg: "success",
Code: 200,
}
c.JSON(200, d)
}
直接通过gin.H返回
直接用gin.H将json数据进行返回,返回效果和上面效果一样
func JsonHandler(c *gin.Context) {
c.JSON(200, gin.H{
"msg": "success",
"code": 200,
})
}
路由重定向
func main() {
r := gin.Default()
r.GET("/response/json", JsonHandler)
r.GET("/response/baidu", ResponseRedirHandler)
r.Run(":8080")
}
func ResponseHandler(c *gin.Context) {
msg := "success response"
c.String(200, msg)
}
func JsonHandler(c *gin.Context) {
c.JSON(200, gin.H{
"msg": "success",
"code": 200,
})
}
func ResponseRedirHandler(c *gin.Context) {
c.Redirect(302, "https://www.baidu.com")
}
路由分发
一个项目有非常多的模块,每个模块维护自己的路由.主路由在main.go中进行注册
初始化项目
go mod init demo_route_layer // 初始化项目
go mod tidy // 更新项目中使用的模块
go get github.com/gin-gonic/gin // 下载go模块
main.go
import (
"demo_route_layer/routers" // 导入本地模块
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// 注册路由
routers.LoadUsers(r)
routers.LoadBook(r)
r.Run(":8080")
}
routers/users.go
// 分层注册路由
func LoadUsers(r *gin.Engine) {
r.GET("/user", UserHandler)
}
func UserHandler(c *gin.Context) {
c.String(200, "用户模块分发")
}
routers/book
import "github.com/gin-gonic/gin"
func LoadBook(r *gin.Engine) {
r.GET("/book", BooksHandler)
}
func BooksHandler(c *gin.Context) {
c.String(200, "图书模块返回")
}
会话处理
Cookie
Cookie介绍
- HTTP是无状态协议,服务器不能记录浏览器的访问状态,也就是说服务器不能区分两次请求是否由同一个客户端发出
- Cookie就是解决HTTP协议无状态的方案之一,中文是小甜饼的意思
- Cookie实际上就是服务器保存在浏览器上的一段信息。浏览器有了Cookie之后,每次向服务器发送请求时都会同时将该信息发送给服务器,服务器收到请求后,就可以根据该信息处理请求
- Cookie由服务器创建,并发送给浏览器,最终由浏览器保存
cookie用途
测试服务端发送cookie给客户端,客户端请求时携带cookie
Cookie缺点
- 不安全,明文
- 增加带宽消耗
- 可以被禁用
- cookie数量有上限(每个浏览器不同)
Sessions
- 简单的API:将其用作设置签名(以及可选的加密)cookie的简便方法。
- 内置的后端可将session存储在cookie或文件系统中。
- Flash消息:一直持续读取的session值。
- 切换session持久性(又称“记住我”)和设置其他属性的便捷方法。
- 旋转身份验证和加密密钥的机制。
- 每个请求有多个session,即使使用不同的后端也是如此。
- 自定义session后端的接口和基础结构:可以使用通用API检索并批量保存来自不同商店的session。