介绍
Gin 是一个用 Go (Golang) 编写的 Web 框架。 它具有类似 martini 的 API,性能要好得多,多亏了 httprouter,速度提高了 40 倍。 如果您需要性能和良好的生产力,您一定会喜欢 Gin。
安装
go get -u github.com/gin-gonic/gin
快速开始
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}
接受请求参数
公共部分
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
router := gin.Default()
//调用方法
router.Run(":8080")
}
get请求
获取路径上数据(post一样)
使用gin.Context.Query("参数名")获取
func main() {
router := gin.Default()
testGetUrl(router)
router.Run(":8080")
}
func testGetUrl(router *gin.Engine) {
router.GET("/getUrl", func(c *gin.Context) {
// 获取参数值
name := c.Query("name")
age := c.Query("age")
// 返回响应
c.JSON(http.StatusOK, gin.H{
"name": name,
"age": age,
})
})
}
获取路由参数(post一样)
package main
import (
"github.com/gin-gonic/gin"
"io"
"net/http"
"net/url"
"os"
)
func main() {
router := gin.Default()
testRouteParams(router)
router.Run(":8080")
}
func testRouteParams(router *gin.Engine) {
router.GET("/routeParams/:name/:age", func(c *gin.Context) {
// 获取参数值
name := c.Param("name")
age := c.Param("age")
// 返回响应
c.JSON(http.StatusOK, gin.H{
"name": name,
"age": age,
})
})
}
获取cookie(post一样)
package main
import (
"github.com/gin-gonic/gin"
"io"
"net/http"
"net/url"
"os"
)
func main() {
router := gin.Default()
testCookies(router)
router.Run(":8080")
}
func testCookies(router *gin.Engine) {
router.GET("/cookies", func(c *gin.Context) {
// 获取参数值
name, _ := c.Cookie("name")
age, _ := c.Cookie("age")
// 返回响应
c.JSON(http.StatusOK, gin.H{
"name": name,
"age": age,
})
})
}
获取表单参数(post一样)
func main() {
router := gin.Default()
testGetForm(router)
router.Run(":8080")
}
func testGetForm(router *gin.Engine) {
router.GET("/getForm", func(c *gin.Context) {
var form User
// 在这种情况下,将自动选择合适的绑定
if c.ShouldBind(&form) == nil {
// 返回响应
c.JSON(http.StatusOK, gin.H{
"name": form.Name,
"age": form.Age,
})
}
})
}
获取请求头(post一样)
func main() {
router := gin.Default()
testGetHeader(router)
router.Run(":8080")
}
func testGetHeader(router *gin.Engine) {
router.GET("/getHeader", func(c *gin.Context) {
// 获取参数值
name := c.GetHeader("name")
age := c.GetHeader("age")
contentType := c.GetHeader("Content-Type")
// 返回响应
c.JSON(http.StatusOK, gin.H{
"name": name,
"age": age,
"contentType": contentType,
})
})
}
post请求
获取请求体数据
和post表单一样
func main() {
router := gin.Default()
testPostForm(router)
router.Run(":8080")
}
func testPostForm(router *gin.Engine) {
router.POST("/postForm", func(c *gin.Context) {
var form User
// 在这种情况下,将自动选择合适的绑定
if c.ShouldBind(&form) == nil {
// 返回响应
c.JSON(http.StatusOK, gin.H{
"name": form.Name,
"age": form.Age,
})
}
})
}
文件上传下载
上传单个文件
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
router := gin.Default()
testUpload(router)
router.Run(":8080")
}
func testUpload(router *gin.Engine) {
// 为 multipart forms 设置较低的内存限制 (默认是 32 MiB)
router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *gin.Context) {
// 单文件
file, _ := c.FormFile("file")
dst := file.Filename
// 上传文件至指定的完整文件路径
c.SaveUploadedFile(file, dst)
// 返回响应
c.JSON(http.StatusOK, gin.H{
"name": file.Filename,
})
})
}
上传多个文件
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
router := gin.Default()
testUploadMany(router)
router.Run(":8080")
}
func testUploadMany(router *gin.Engine) {
// 为 multipart forms 设置较低的内存限制 (默认是 32 MiB)
router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/uploadMany", func(c *gin.Context) {
// Multipart form
form, _ := c.MultipartForm()
fileNames := make([]string, 0)
files := form.File["fileList"]
for _, file := range files {
// 上传文件至指定目录
c.SaveUploadedFile(file, "filedir/"+file.Filename)
fileNames = append(fileNames, file.Filename)
}
// 返回响应
c.JSON(http.StatusOK, gin.H{
"name": fileNames,
})
})
}
下载文件
package main
import (
"github.com/gin-gonic/gin"
"io"
"net/http"
"net/url"
"os"
)
func main() {
router := gin.Default()
testDownload(router)
router.Run(":8080")
}
func testDownload(router *gin.Engine) {
router.POST("/download", func(c *gin.Context) {
// 获取文件路径
targetFileName := "照片1.png"
filePath := "filedir/" + targetFileName
// 检查文件是否存在
_, err := os.Stat(filePath)
if os.IsNotExist(err) {
c.String(http.StatusNotFound, "File not found")
return
}
//中文名称会乱码,导致下载失败,所以需要编码
name := url.QueryEscape(targetFileName)
// 设置响应头,指定文件名和内容类型
c.Header("Content-Disposition", "attachment; filename="+name)
c.Header("Content-Type", "application/octet-stream")
// 打开文件
file, err := os.Open(filePath)
if err != nil {
c.String(http.StatusInternalServerError, "Error opening file")
return
}
defer file.Close()
// 将文件内容写入响应体
_, err = io.Copy(c.Writer, file)
if err != nil {
c.String(http.StatusInternalServerError, "Error copying file")
return
}
})
}
由于是postman下载的,没法解析为中文,用浏览器下载就没问题了
日志
func main() {
// 禁用控制台颜色,将日志写入文件时不需要控制台颜色。
gin.DisableConsoleColor()
// 记录到文件。
f, _ := os.Create("gin.log")
gin.DefaultWriter = io.MultiWriter(f)
// 如果需要同时将日志写入文件和控制台,请使用以下代码。
// gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
router := gin.Default()
router.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
router.Run(":8080")
}
路由组
func main() {
router := gin.Default()
// 简单的路由组: v1
v1 := router.Group("/v1")
{
v1.POST("/login", loginEndpoint)
v1.POST("/submit", submitEndpoint)
v1.POST("/read", readEndpoint)
}
// 简单的路由组: v2
v2 := router.Group("/v2")
{
v2.POST("/login", loginEndpoint)
v2.POST("/submit", submitEndpoint)
v2.POST("/read", readEndpoint)
}
router.Run(":8080")
}
运行多个服务
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,
}
g.Go(func() error {
return server01.ListenAndServe()
})
g.Go(func() error {
return server02.ListenAndServe()
})
if err := g.Wait(); err != nil {
log.Fatal(err)
}
}
重定向
HTTP 重定向很容易。 内部、外部重定向均支持。
r.GET("/test", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "http://www.google.com/")
})
通过 POST 方法进行 HTTP 重定向。请参考 issue:#444
r.POST("/test", func(c *gin.Context) {
c.Redirect(http.StatusFound, "/foo")
})
路由重定向,使用 HandleContext
:
r.GET("/test", func(c *gin.Context) {
c.Request.URL.Path = "/test2"
r.HandleContext(c)
})
r.GET("/test2", func(c *gin.Context) {
c.JSON(200, gin.H{"hello": "world"})
})