介绍
- Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确,具有快速灵活,容错方便等特点
- 对于golang而言,web框架的依赖要远比Python,Java之类的要小。自身的
net/http
足够简单,性能也非常不错 - 借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范
安装
go get -u github.com/gin-gonic/gin
第一个gin程序
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
// 1.创建路由
r := gin.Default()
// 2.绑定路由规则,执行的函数
// gin.Context,封装了request和response
r.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "hello World!")
})
// 3.监听端口,默认在8080
// Run("里面不指定端口号默认为8080")
r.Run(":8000")
}
路由
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "hello word")
})
r.POST("/xxxpost",getting)
r.PUT("/xxxput")
//监听端口默认为8080
r.Run(":8000")
}
路由重定向
路由重定向,使用HandleContext
:
r.GET("/test", func(c *gin.Context) {
// 指定重定向的URL
c.Request.URL.Path = "/test2"
r.HandleContext(c)
})
r.GET("/test2", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"hello": "world"})
})
返回数据渲染
JSON渲染
func main() {
r := gin.Default()
// gin.H 是map[string]interface{}的缩写
r.GET("/someJSON", func(c *gin.Context) {
// 方式一:自己拼接JSON
c.JSON(http.StatusOK, gin.H{"message": "Hello world!"})
})
r.GET("/moreJSON", func(c *gin.Context) {
// 方法二:使用结构体
var msg struct {
Name string `json:"user"`
Message string
Age int
}
msg.Name = "小王子"
msg.Message = "Hello world!"
msg.Age = 18
c.JSON(http.StatusOK, msg)
})
r.Run(":8080")
}
XML渲染
注意需要使用具名的结构体类型。
func main() {
r := gin.Default()
// gin.H 是map[string]interface{}的缩写
r.GET("/someXML", func(c *gin.Context) {
// 方式一:自己拼接JSON
c.XML(http.StatusOK, gin.H{"message": "Hello world!"})
})
r.GET("/moreXML", func(c *gin.Context) {
// 方法二:使用结构体
type MessageRecord struct {
Name string
Message string
Age int
}
var msg MessageRecord
msg.Name = "小王子"
msg.Message = "Hello world!"
msg.Age = 18
c.XML(http.StatusOK, msg)
})
r.Run(":8080")
}
YMAL渲染
r.GET("/someYAML", func(c *gin.Context) {
c.YAML(http.StatusOK, gin.H{"message": "ok", "status": http.StatusOK})
})
protobuf渲染
r.GET("/someProtoBuf", func(c *gin.Context) {
reps := []int64{int64(1), int64(2)}
label := "test"
// protobuf 的具体定义写在 testdata/protoexample 文件中。
data := &protoexample.Test{
Label: &label,
Reps: reps,
}
// 请注意,数据在响应中变为二进制数据
// 将输出被 protoexample.Test protobuf 序列化了的数据
c.ProtoBuf(http.StatusOK, data)
})
获取参数
获取json参数
当前端请求的数据通过JSON提交时,例如向/json
发送一个POST请求,则获取请求参数的方式如下:
r.POST("/json", func(c *gin.Context) {
// 注意:下面为了举例子方便,暂时忽略了错误处理
b, _ := c.GetRawData() // 从c.Request.Body读取请求数据
// 定义map或结构体
var m map[string]interface{}
// 反序列化
_ = json.Unmarshal(b, &m)
c.JSON(http.StatusOK, m)
})
请求参数
使用Param获取
r.GET("/user/:name/*action", func(c *gin.Context) {
name := c.Param("name") // 使用Param获取
action := c.Param("action")
package main
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/user/:name/*action", func(c *gin.Context) {
name := c.Param("name")
action := c.Param("action")
//截取/
action = strings.Trim(action, "/")
c.String(http.StatusOK, name+" is "+action)
})
//默认为监听8080端口
r.Run(":8000")
}
url参数
- URL参数可以通过DefaultQuery()或Query()方法获取
- DefaultQuery()若参数不村则,返回默认值,Query()若不存在,返回空串
- API ? name=zs
r.GET("/", func(c *gin.Context) {
name := c.Query("name")
age := c.DefaultQuery("age", "18")
c.JSON(http.StatusOK, gin.H{
"msg": "ok",
"name": name,
"age": age,
})
})
表单参数
r.POST("/post", func(c *gin.Context) {
username := c.PostForm("username")
password := c.PostForm("password")
c.JSON(200, gin.H{
"username": username,
"password": password,
})
})
上传文件
单个文件
r.POST("/upload", func(c *gin.Context) {
_, header, err := c.Request.FormFile("file")
if err != nil {
panic(err.Error())
}
c.SaveUploadedFile(header, "./media/"+header.Filename) //保存文件
c.JSON(200, gin.H{
"msg": "上传成功",
"file": header.Filename,
})
})
r.POST("/upload2", func(c *gin.Context) {
fileHeader, err := c.FormFile("file")
if err != nil {
panic(err.Error())
}
c.SaveUploadedFile(fileHeader, "./media/"+fileHeader.Filename)
c.JSON(200, gin.H{
"msg": "上传成功",
"file": fileHeader.Filename,
})
})
特定文件
r.POST("/upload", func(c *gin.Context) {
_, header, err := c.Request.FormFile("file")
if err != nil {
panic(err.Error())
}
c.SaveUploadedFile(header, "./media/"+header.Filename)
if header.Size > 1024*1024 {
panic("文件太大")
} else if header.Header.Get("Content-Type") != "image/png" {
panic("只能上传image/png")
} else {
c.JSON(200, gin.H{
"msg": "上传成功",
"file": header.Filename,
})
}
})
多个文件
r.MaxMultipartMemory = 8 << 20
r.POST("/upload", func(c *gin.Context) {
form, err := c.MultipartForm()
if err != nil {
c.String(http.StatusBadRequest, fmt.Sprintf("get err %s", err.Error()))
}
// 获取所有图片
files := form.File["files"]
// 遍历所有图片
for _, file := range files {
// 逐个存
if err := c.SaveUploadedFile(file, file.Filename); err != nil {
c.String(http.StatusBadRequest, fmt.Sprintf("upload err %s", err.Error()))
return
}
}
c.String(200, fmt.Sprintf("upload ok %d files", len(files)))
})
routes group
- routes group是为了管理一些相同的URL
- 我们可以将拥有共同URL前缀的路由划分为一个路由组。习惯性一对
{}
包裹同组的路由,这只是为了看着清晰,你用不用{}
包裹功能上没什么区别。
// gin的helloWorld
func main() {
// 1.创建路由
// 默认使用了2个中间件Logger(), Recovery()
r := gin.Default()
// 路由组1 ,处理GET请求
v1 := r.Group("/v1")
// {} 是书写规范
{
v1.GET("/login", login)
v1.GET("submit", submit)
}
v2 := r.Group("/v2")
{
v2.POST("/login", login)
v2.POST("/submit", submit)
}
r.Run(":8000")
}
func login(c *gin.Context) {
name := c.DefaultQuery("name", "jack")
c.String(200, fmt.Sprintf("hello %s\n", name))
}
func submit(c *gin.Context) {
name := c.DefaultQuery("name", "lily")
c.String(200, fmt.Sprintf("hello %s\n", name))
}
404页面
package main
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/user", func(c *gin.Context) {
//指定默认值
//http://localhost:8080/user 才会打印出来默认的值
name := c.DefaultQuery("name", "枯藤")
c.String(http.StatusOK, fmt.Sprintf("hello %s", name))2020-08-05 09:22:11 星期三
})
r.NoRoute(func(c *gin.Context) {
c.String(http.StatusNotFound, "404 not found2222")
})
r.Run()
中间件
注册中间件必须返回gin.HandlerFunc类型
func(c *gin.Context) { .... }的类型极为gin.HandlerFunc
// 调用该请求的剩余处理程序
c.Next() // 通过
c.Set("name", "小王子") // 可以通过c.Set在请求上下文中设置值,后续的处理函数能够取到该值
// 不调用该请求的剩余处理程序
c.Abort() // 不通过
全局中间件
Use注册全局中间件
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func Middleware() gin.HandlerFunc {
// 逻辑
// 操作数据库 ...
return func(c *gin.Context) {
fmt.Println("gin全局中间件")
c.Next()
}
}
func main() {
r := gin.Default()
r.Use(Middleware())
r.GET("/", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "hello word",
})
})
r.Run()
}
注册局部中间件
方式1
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func Middleware() gin.HandlerFunc {
return func(c *gin.Context) {
fmt.Println("gin全局中间件")
c.Next()
}
}
func main() {
r := gin.Default()
r.Use(Middleware())
r.GET("/",Middleware(), func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "hello word",
})
})
r.Run()
}
方式2
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
fmt.Println("gin局部中间件")
c.Next()
}, func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "hello word",
})
})
r.Run()
}
为路由组注册中间件
func Middleware() gin.HandlerFunc {
return func(c *gin.Context) {
fmt.Println("gin为路由组注册中间件")
c.Next()
}
}
shopGroup := r.Group("/shop", Middleware())
{
shopGroup.GET("/index", func(c *gin.Context) {...})
...
}
运行多个服务
我们可以在多个端口启动服务,例如:
package main
import (
"log"
"net/http"
"time"
"github.com/gin-gonic/gin"
"golang.org/x/sync/errgroup"
)
var (
g errgroup.Group
)
func router01() http.Handler {
e := gin.New()
e.Use(gin.Recovery())
e.GET("/", func(c *gin.Context) {
c.JSON(
http.StatusOK,
gin.H{
"code": http.StatusOK,
"error": "Welcome server 01",
},
)
})
return e
}
func router02() http.Handler {
e := gin.New()
e.Use(gin.Recovery())
e.GET("/", func(c *gin.Context) {
c.JSON(
http.StatusOK,
gin.H{
"code": http.StatusOK,
"error": "Welcome server 02",
},
)
})
return e
}
func main() {
server01 := &http.Server{
Addr: ":8080",
Handler: router01(),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
server02 := &http.Server{
Addr: ":8081",
Handler: router02(),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
// 借助errgroup.Group或者自行开启两个goroutine分别启动两个服务
g.Go(func() error {
return server01.ListenAndServe()
})
g.Go(func() error {
return server02.ListenAndServe()
})
if err := g.Wait(); err != nil {
log.Fatal(err)
}
}
标签:教程,http,func,GET,Context,gin,name
From: https://www.cnblogs.com/yangyucai/p/16855895.html