目录
【基本的HTTP请求】
GET请求
POST请求
文件操作
重定向
HTTP获取三方服务数据
不同格式的内容输出
异步请求
【中间件】
中间件校验数据
登录中间件
【启动多个服务】
Gin框架官网:https://gin-gonic.com/zh-cn/,新增一个Go文件,引入 github.com/gin-gonic/gin 即可使用Gin框架。
示例代码如下:
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()//路由引擎
r.GET("/get",getMsg) //get方法
//r.Run("127.0.0.1:9090")
r.Run(":9090") //如果不指定IP地址、端口号,默认为本机IP地址、8080端口
}
func getMsg(c *gin.Context) {
name:=c.Query("name")
//返回字符串类型数据
//c.String(http.StatusOK,"欢迎您:%s",name)
//返回json数据
c.JSON(http.StatusOK,gin.H{
"code":http.StatusOK,//状态
"msg":"成功", //描述信息
"data":"欢迎您:"+name,//数据
})
}
浏览器访问 http://127.0.0.1:8080/get?name=zhangsan
r.POST("/post", controllers.BasicPostData)
func BasicPostData(c *gin.Context) {
name := c.DefaultPostForm("name", "Gin") //获取body中的数据(form形式)
fmt.Println("name", name)
form, err := c.GetPostForm("name") //获取body中的数据(form形式)
fmt.Println(form, err)
c.JSON(http.StatusOK, "欢迎您:"+name)
}
通过postman请求 http://127.0.0.1:8080/post
主要演示从服务器下载文件和上传文件到服务器,代码如下:
r.GET("/get-file", controllers.GetFile)
r.POST("/upload-file", controllers.UploadFile)
r.POST("/upload-file-batch", controllers.UploadFileBatch)
// 从服务端获取或下载文件
func GetFile(c *gin.Context) {
fileName := "/home/rx/Documents/tmp/1.jpeg" //输出图片
//fileName := "/home/rx/Documents/tmp/file.zip" //下载文件
c.File(fileName)
}
// 将文件上传到服务端
func UploadFile(c *gin.Context) {
file, err := c.FormFile("fileName")
if err != nil {
c.String(http.StatusBadRequest, "文件上传错误!")
}
//存储路径
dst := "/home/rx/Documents/tmp/"
c.SaveUploadedFile(file, dst+file.Filename) //存储文件
c.String(http.StatusOK, fmt.Sprintf("%s 上传完成", file.Filename))
}
// 批量将文件上传到服务端
func UploadFileBatch(c *gin.Context) {
//多文件的上传
form, err := c.MultipartForm() //获取form
if err != nil {
c.String(http.StatusBadRequest, "上传文件错误")
}
files := form.File["fileName"] //上传的所有文件
dst := "/home/rx/Documents/tmp/"
//遍历文件
for _, file := range files {
c.SaveUploadedFile(file, dst+file.Filename)
}
c.String(http.StatusOK, fmt.Sprintf("%d 个文件上传完成!", len(files)))
}
执行效果如下:
//重定向到另外的域名
r.GET("/redirect1", func(c *gin.Context) {
url := "http://www.baidu.com" //重定向的URL
c.Redirect(http.StatusMovedPermanently, url) //301永久重定向
})
//重定向到当前服务的其它路由
r.GET("/redirect2", func(c *gin.Context) {
c.Request.URL.Path = "/get" //重定向到 http://127.0.0.1:8080/get
r.HandleContext(c)
})
访问 http://127.0.0.1:8080/redirect1 会直接跳转到 “baidu.com”;访问 http://127.0.0.1:8080/redirect2 页面不会跳转,但会显示 /get 路由的内容。
如果你用过PHP,一定知道PHP中有一个强大的函数是CURL,可以通过HTTP请求获取和发送数据与三方服务交互。Gin框架中实现这个功能也很简单,直接看代码:
r.GET("/curl", controllers.BasicCurlData)
func BasicCurlData(c *gin.Context) {
url := "https://profile-avatar.csdnimg.cn/2334e87504d344588c50c0125c4e39da_rxbook.jpg!1"
response, err := http.Get(url)
if err != nil || response.StatusCode != http.StatusOK {
c.Status(http.StatusServiceUnavailable)
return
}
body := response.Body
contentLength := response.ContentLength
contentType := response.Header.Get("Content-Type")
//数据写入响应体
c.DataFromReader(http.StatusOK, contentLength, contentType, body, nil)
}
请求 http://127.0.0.1:8080/curl 可以获取到设定的URL中的内容。
可以输出JSON、XML、YAML等格式:
r.GET("/output", controllers.Output)
func Output(c *gin.Context) {
flag := c.Query("flag")
if flag == "json" {
outputJson(c)
} else if flag == "xml" {
outputXML(c)
} else if flag == "yaml" {
outputYAML(c)
}
}
// 输出json
func outputJson(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"code": 200,
"message": "success",
})
}
// 输出XML
func outputXML(c *gin.Context) {
type Message struct {
Code int
Message string
}
info := Message{}
info.Code = 200
info.Message = "Success"
c.XML(http.StatusOK, info)
}
// 输出YAML
func outputYAML(c *gin.Context) {
c.YAML(http.StatusOK, gin.H{
"code": 200,
"message": "输出YAML内容",
})
}
假设某个方法需要执行一段很耗时的任务,如果是同步执行,效果如下:
func BasicPostData(c *gin.Context) {
//耗时任务
//同步执行三个任务
for i := 0; i < 3; i++ {
longTimeCost(c, i)
}
}
func longTimeCost(cp *gin.Context, i int) {
println("第" + strconv.Itoa(i) + "个任务开始执行:" + cp.Request.URL.Path)
time.Sleep(time.Second * 5)
println("第" + strconv.Itoa(i) + "个任务执行完毕")
}
改成异步:
//异步执行三个任务
for i := 0; i < 3; i++ {
go longTimeCost(c, i)
}
使用中间件可以对数据进行规则校验,比如校验用户名是否合法,金额是否是数字类型等等。下面是一个简单的示例,校验token是否合法:
func Router() *gin.Engine {
r := gin.Default() //默认路由引擎:包括 Logger and Recovery middleware
//r:=gin.New() //没有任何中间件的路由引擎
r.Use(service.Middleware()) //中间件校验
r.POST("/post", controllers.BasicPostData)
return r
}
// 中间件校验数据
func Middleware() gin.HandlerFunc {
return func(c *gin.Context) {
fmt.Println(">> 中间件执行开始 <<")
token := c.Query("token")
if token != "123456" {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
"code": http.StatusBadRequest,
"msg": "token错误",
"data": nil,
})
return
}
fmt.Println(">> 中间件执行结束 <<")
c.Next() //执行后续操作
}
}
然后再调用接口,如果token不正确则会被拦截:
使用Gin框架自带的 `BasicAuth` 方法可以快速实现一个用户登录校验的中间件,代码如下:
func Router() *gin.Engine {
r := gin.Default() //默认路由引擎:包括 Logger and Recovery middleware
//r:=gin.New() //没有任何中间件的路由引擎
r.Use(service.AuthMiddleware()) //登录中间件校验
r.POST("/get", controllers.BasicGetData)
return r
}
// 登录中间件
func AuthMiddleware() gin.HandlerFunc {
//初始化用户
accounts := gin.Accounts{ // gin.Accounts 是 map[string]string 类型
"admin": "123456",
"zhangsan": "888888",
}
//动态添加用户
accounts["lisi"] = "666666"
accounts["wangwu"] = "777777"
//将用户添加到登录中间件中
auth := gin.BasicAuth(accounts)
//获取登录的用户信息
loginUserName := c.MustGet(gin.AuthUserKey).(string)
fmt.Println("loginUserName", loginUserName)
return auth
}
打开浏览器的访问效果(第一次需要输入用户名和密码,下次不需要,直到重新打开浏览器):
在一个Gin框架中启动多个服务,代码如下:
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"golang.org/x/sync/errgroup"
"net/http"
"time"
)
var g errgroup.Group
func main() {
//服务器1:
server01 := &http.Server{
Addr: ":8081",
Handler: router01(),
ReadTimeout: 5 * time.Second, //读取超时时间
WriteTimeout: 10 * time.Second, //写入超时时间
}
//服务器2:
server02 := &http.Server{
Addr: ":8082",
Handler: router02(),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
//开启服务
g.Go(func() error { //开启服务器程序1
return server01.ListenAndServe()
})
g.Go(func() error { //开启服务器程序2
return server02.ListenAndServe()
})
//让监听程序一直处于等待状态
if err := g.Wait(); err != nil {
fmt.Println("执行失败:", err)
}
}
func router01() http.Handler {
r1 := gin.Default()
r1.GET("/", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"code": http.StatusOK,
"msg": "服务器01的响应",
},
)
})
return r1
}
func router02() http.Handler {
r1 := gin.Default()
r1.GET("/", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"code": http.StatusOK,
"msg": "服务器02的响应",
},
)
})
return r1
}
运行后,分别访问两个端口: