Gin学习

最简单的实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "ok!",
})
})
r.Run("0.0.0.0:7777")
}

获取路由中的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
r := gin.Default()
r.Any("/u/:name/*pass", func(c *gin.Context) {
name := c.Param("name")
pass := c.Param("pass")
c.JSON(http.StatusOK, gin.H{
"name":name,
"pass":pass,
})
})

r.Run("0.0.0.0:7777")
}

访问:/u/qiyou/abc,返回的是{"name":"qiyou","pass":"/abc"},注意abc这里有一个斜杠

获取GET参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
name := c.DefaultQuery("name","qiyou")
pass:=c.Query("pass")
c.JSON(http.StatusOK, gin.H{
"name":name,
"pass":pass,
})
})

r.Run("0.0.0.0:7777")
}

DefaultQuery: 如果请求的参数没有包含key,那么默认为第二个参数。

获取POST参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
r := gin.Default()
r.POST("/", func(c *gin.Context) {
name := c.DefaultPostForm("name","qiyou")
pass:=c.PostForm("pass")
c.JSON(http.StatusOK, gin.H{
"name":name,
"pass":pass,
})
})

r.Run("0.0.0.0:7777")
}

DefaultPostForm: 如果请求的参数没有包含key,那么默认为第二个参数。

同时获取GET和POST参数

注意:GET路由不支持POST请求,如果发送POST那么将会放回404,POST路由也是如此

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
r := gin.Default()
r.POST("/", func(c *gin.Context) {
name := c.DefaultPostForm("name","qiyou")
pass:=c.PostForm("pass")
age:=c.Query("age")
sex:=c.DefaultQuery("sex","male")
c.JSON(http.StatusOK, gin.H{
"name":name,
"pass":pass,
"age":age,
"sex":sex,
})
})

r.Run("0.0.0.0:7777")
}

上传文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
r := gin.Default()
r.POST("/upload", func(c *gin.Context) {
file,_:=c.FormFile("files")
c.String(http.StatusOK,file.Filename)
if err:=c.SaveUploadedFile(file,"./abc.txt");err!=nil{
c.String(http.StatusInternalServerError,err.Error())
}else{
c.String(http.StatusOK,"Success!")
}

})

r.Run("0.0.0.0:7777")
}

测试:curl -F "files=@abc.txt" http://192.168.43.212:7777/upload

多文件上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
r := gin.Default()
r.POST("/upload", func(c *gin.Context) {
all,_:=c.MultipartForm()
files:=all.File["files[]"]
for _,file:=range files{
if err:=c.SaveUploadedFile(file,"./abc.txt");err!=nil{
c.String(http.StatusInternalServerError,err.Error())
}else{
c.String(http.StatusOK,"Success,"+file.Filename)
}
}

})

r.Run("0.0.0.0:7777")
}

测试:curl -F "files[]=@main.go" -F "files[]=@abc.txt" http://192.168.43.212:7777/upload

路由分组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main

import (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
r := gin.Default()
blog:=r.Group("blog")
{
blog.GET("/comments/",func(c *gin.Context){ //等价于/blog/comments/
c.String(http.StatusOK,"comments")
})

blog.GET("/submits/",func(c *gin.Context){ //等价于/blog/submits/
c.String(http.StatusOK,"submits")
})
}

www:=r.Group("www")
{
www.GET("/users/",func(c *gin.Context){ //等价于/www/users/
c.String(http.StatusOK,"users")
})

www.GET("/posts",func(c *gin.Context){ //等价于/www/posts/
c.String(http.StatusOK,"posts")
})
}

r.Run("0.0.0.0:7777")
}

自定义中间件

使用

1
r := gin.New()

代替

1
r := gin.Default() // 默认启动方式,包含 Logger、Recovery 中间件

简单的实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
"github.com/gin-gonic/gin"
)

func main() {
r := gin.New()
//添加中间件
r.Use(gin.Recovery())
r.Use(gin.Logger())
r.GET("/test/",func(c *gin.Context){
c.String(200,"test")
})

test:=r.Group("/www/")
//给路由组添加中间件
test.Use(gin.Recovery())
test.Use(gin.Logger())
{
test.GET("/abc/",func(c *gin.Context){
c.String(200,"abc")
})
}
r.Run(":7777")
}

日志文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
"github.com/gin-gonic/gin"
"io"
"os"
)

func main() {
gin.DisableConsoleColor()
f,_:=os.Create("log.log")
//只写入文件,不在控制台输出
//gin.DefaultWriter = io.MultiWriter(f)
gin.DefaultWriter = io.MultiWriter(f,os.Stdout) //既写入文件,也在控制台输出。
r:=gin.Default()
r.GET("/test/",func(c *gin.Context){
c.String(200,"test")
})
r.Run(":7777")
}

自定义日志格式,输出类似于apache日志格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package main

import (
"fmt"
"github.com/gin-gonic/gin"
"time"
)

func main() {
router := gin.New()

// LoggerWithFormatter 中间件会将日志写入 gin.DefaultWriter
// By default gin.DefaultWriter = os.Stdout
router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {

// 你的自定义格式
return fmt.Sprintf("%s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n",
param.ClientIP,
param.TimeStamp.Format(time.RFC1123),
param.Method,
param.Path,
param.Request.Proto,
param.StatusCode,
param.Latency,
param.Request.UserAgent(),
param.ErrorMessage,
)
}))
router.Use(gin.Recovery())

router.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
router.Run(":7777")
}

模型绑定

要注意几个点是:

  1. tag必须要有,以kv的形式存在,例如:json:"Fieldame",而且tag里面的key-value冒号之间不能用空格
  2. form表示的是GET和POST,json表示的是json,xml表示的是xml
  3. binding:"required"表示的是一定要有值,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package main

import (
"github.com/gin-gonic/gin"
)

type Login struct {
User string `form:"user" json:"user" xml:"user" binding:"required"`
Password string `form:"password" json:"password" xml:"password" binding:"required"`
}

func main() {
router := gin.New()
var test Login
router.POST("/loginJSON",func(c *gin.Context){
if err:=c.ShouldBindJSON(&test);err!=nil{
c.JSON(400,gin.H{"message":"login failed"})
}else{
c.JSON(200,gin.H{
"user":test.User,
"pass":test.Password,
})
}

})

router.POST("/loginForm",func(c *gin.Context){
if err:=c.ShouldBind(&test);err!=nil{
c.JSON(400,gin.H{"message":"login failed"})
}else{
c.JSON(200,gin.H{
"user":test.User,
"pass":test.Password,
})
}

})
router.Run(":7777")
}

如果只想绑定GET参数不绑定POST参数,可以使用ShouldBindQuery

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
"github.com/gin-gonic/gin"
)

type Login struct {
User string `form:"user" binding:"required"`
Password string `form:"password" binding:"required"`
}

func main() {
router := gin.New()
var test Login
router.POST("/login",func(c *gin.Context){
if err:=c.ShouldBindQuery(&test);err!=nil{
c.JSON(400,gin.H{"message":"login failed"})
}else{
c.JSON(200,gin.H{
"user":test.User,
"pass":test.Password,
})
}

})
router.Run(":7777")
}

接收POST或者GET

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main

import (
"github.com/gin-gonic/gin"
)

type Login struct {
User string `form:"user" json:"user" xml:"user" binding:"required"`
Password string `form:"password" json:"password" xml:"password" binding:"required"`
}

func main() {
router := gin.New()
var test Login
router.POST("/login",func(c *gin.Context){
// 如果是Get,那么接收不到请求中的Post的数据
// 如果是Post, 首先判断 `content-type` 的类型 `JSON` or `XML`, 然后使用对应的绑定器获取数据.
//https://github.com/gin-gonic/gin/blob/master/binding/binding.go#L48
if err:=c.ShouldBind(&test);err!=nil{
c.JSON(400,gin.H{"message":"login failed"})
}else{
c.JSON(200,gin.H{
"user":test.User,
"pass":test.Password,
})
}

})
router.Run(":7777")
}

绑定uri

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
"github.com/gin-gonic/gin"
)

type Login struct {
Path string `uri:"path" binding:"required"`
User string `uri:"user" binding:"required"`
}

func main() {
router := gin.New()
var test Login
router.POST("/:user/:path",func(c *gin.Context){
if err:=c.ShouldBindUri(&test);err!=nil{
c.JSON(400,gin.H{"message":"login failed"})
}else{
c.JSON(200,gin.H{
"user":test.User,
"pass":test.Path,
})
}
})
router.Run(":7777")
}

只绑定POST

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
)

type Login struct {
Username string `form:"username" binding:"required"`
Password string `form:"password" binding:"required"`
}

func main() {
router := gin.New()
var test Login
router.POST("/login",func(c *gin.Context){
if err:=c.ShouldBindWith(&test,binding.Form);err!=nil{
c.JSON(400,gin.H{"message":"login failed"})
}else{
c.JSON(200,gin.H{
"user":test.Username,
"pass":test.Password,
})
}
})
router.Run(":7777")
}

XML和JSON、YAML格式渲染

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

import (
"github.com/gin-gonic/gin"
)

type Login struct {
Username string `form:"username" binding:"required"`
Password string `form:"password" binding:"required"`
}

func main() {
router := gin.Default()
var test =Login{
Username: "abc",
Password: "abc",
}
router.POST("/json",func(c *gin.Context){

c.JSON(200,test)
})

router.POST("/xml",func(c *gin.Context){
c.XML(200,gin.H{"status":200,"msg":"suceess xml"}) //或者使用结构体也可以
})

router.POST("yaml",func(c *gin.Context){
c.YAML(200,gin.H{"status":200,"msg":"suceess yaml"}) //或者使用结构体也可以
})
router.Run(":7777")
}

JSONP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import (
"github.com/gin-gonic/gin"
)

func main() {
router := gin.Default()
param:=map[string]interface{}{
"name":"qiyou",
}

router.GET("/JSONP",func(c *gin.Context){
c.JSONP(200,param)
})
router.Run(":7777")
}

访问/JSONP?callback=call,将会输出call({"name":"qiyou"});

AsciiJSON

将使特殊字符编码

其实默认的c.JSON也会将特殊的HTML字符替换为对应的unicode字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"github.com/gin-gonic/gin"
)

type Login struct {
Username string `form:"username" binding:"required"`
Password string `form:"password" binding:"required"`
}

func main() {
router := gin.Default()
param:=map[string]interface{}{
"name":"<b>test</b>",
}

router.GET("/JSON",func(c *gin.Context){
c.AsciiJSON(200,param)
})
router.Run(":7777")
}

PureJSON

不将特殊字符编码

PS: 该功能在go1.6及以下版本无法实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"github.com/gin-gonic/gin"
)

type Login struct {
Username string `form:"username" binding:"required"`
Password string `form:"password" binding:"required"`
}

func main() {
router := gin.Default()
param:=map[string]interface{}{
"name":"<b>test</b>",
}

router.GET("/JSON",func(c *gin.Context){
c.PureJSON(200,param)
})
router.Run(":7777")
}

静态文件

设置静态文件路径
PS: 这些目录下资源是可以随时更新,而不用重新启动程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
router := gin.Default()
//设置单个文件
router.StaticFile("/1.png","./static/1.png")
//设置一个文件夹
router.StaticFS("/other",http.Dir("./Static"))
router.Run(":7777")
}

返回第三方获取的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
router := gin.Default()
router.GET("/test", func(c *gin.Context) {
response, err := http.Get("https://raw.githubusercontent.com/gin-gonic/logo/master/color.png")
if err != nil || response.StatusCode != http.StatusOK {
c.Status(http.StatusServiceUnavailable)
return
}

reader := response.Body
contentLength := response.ContentLength
contentType := response.Header.Get("Content-Type")

extraHeaders := map[string]string{
"Content-Disposition": `attachment; filename="gopher.png"`,
}

c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders)
})
router.Run(":7777")
}

模板渲染

  1. LoadHTMLGlob(): 支持统配符
  2. LoadHTMLFiles(): 支持多个文件
    PS: LoadHTMLGlob和LoadHTMLFiles只能使用其中一个,否则后者会覆盖掉前者
  3. r.LoadHTMLGlob("template/*")//此处加载html路径只能指定一次,如果指定多次只有最后一次有效
    r.LoadHTMLGlob("view/*") //此处重新设置了html的路径,所以template中的html就无法起作用。
  4. r.LoadHTMLGlob("template/**/*"): 匹配template子文件夹里面的文件,但是不匹配template下的文件,比如只匹配template/test/index.html,但是不匹配template/index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import (
"github.com/gin-gonic/gin"
)

func main() {
router := gin.Default()
router.LoadHTMLFiles("./templates/index.html")
router.GET(("/index"),func(c *gin.Context){
c.HTML(200,"index.html",gin.H{
"title":"test",
"name":"zhangsan",
})
})
router.Run(":7777")
}

index.html

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{.title}}</title>
</head>
<body>
{{.name}}
</body>
</html>

路径不同相同文件名的模板渲染,使用`{{defind "name"}}`定义以下模板名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
"github.com/gin-gonic/gin"
)

func main() {
router := gin.Default()
router.LoadHTMLGlob("./templates/**/*")
router.GET(("/user"),func(c *gin.Context){
c.HTML(200,"users/index.html",gin.H{ //这里填写的是模板名称
"title":"users",
"name":"zhangsan",
})
})

router.GET(("/posts"),func(c *gin.Context){
c.HTML(200,"posts/index.html",gin.H{ //这里填写的是模板名称
"title":"posts",
"name":"lisi",
})
})
router.Run(":7777")
}

posts/index.html内容

1
2
3
4
5
6
7
8
9
10
11
12
13
{{define "posts/index.html"}} //定义模板名称,模板名称可以随便定义,但是建议还是和以目录的形式会好一点

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{.title}}</title>
</head>
<body>
{{.name}}
</body>
</html>
{{end}} //end

自定义模板函数
PS: 默认模板渲染的时候会自动html编码,
router.SetFuncMap必须在router.LoadHTMLGlob前面,否则会宕机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
"github.com/gin-gonic/gin"
"html/template"
"strings"
)

func main() {
router := gin.Default()
router.SetFuncMap(template.FuncMap{
"htmlspecialchars":HTMLspecialchars,
})
router.LoadHTMLGlob("./templates/index.html")
router.GET("/test", func(c *gin.Context) {
c.HTML(200,"index.html", gin.H{
"title":"test",
"name":"<abc>",
})
})
router.Run(":7777")
}

func HTMLspecialchars(s string)string{
return strings.Replace(s,"<","&lt;",-1)
}

重定向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
router := gin.Default()
router.GET("/test",func(c *gin.Context){
c.Redirect(http.StatusMovedPermanently,"http://www.baidu.com") //支持内部重定向和外部重定向
})
router.Run(":7777")
}

验证中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
"github.com/gin-gonic/gin"
"net/http"
)


func main() {
router := gin.Default()
router.Use(gin.BasicAuth(gin.Accounts{
"admin":"admin",
}))
router.GET("/admin",func(c *gin.Context){
c.JSON(http.StatusOK,gin.H{
"hello":c.MustGet(gin.AuthUserKey).(string), //获取用户名
})
})
router.Run(":7777")
}

路由组使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
"github.com/gin-gonic/gin"
)


func main() {
router := gin.Default()
auth:=router.Group("/admin",gin.BasicAuth(gin.Accounts{
"admin":"admin",
}))
auth.GET("/login",func(c *gin.Context){
c.JSON(200,gin.H{
"success":c.MustGet(gin.AuthUserKey).(string),
})
})
router.Run(":7777")
}

自定义中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package main

import (
"github.com/gin-gonic/gin"
"log"
"time"
)


func Logger() gin.HandlerFunc {
return func(c *gin.Context) {
t := time.Now()

// before request
c.Next()
// after request

log.Print("------------------------------------------------------------------------")
log.Print(c.Request.Method)
log.Print(c.Request.Proto)
log.Print(c.Request.Host)
log.Print(c.Request.UserAgent())
log.Print(time.Since(t))
log.Println(c.Writer.Status())
log.Print("------------------------------------------------------------------------")
}
}

func main() {
r := gin.New()
r.Use(Logger())

r.GET("/test", func(c *gin.Context) {
example := c.MustGet("example").(string)

// it would print: "12345"
log.Println(example)
})

// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}

自定义http配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
"github.com/gin-gonic/gin"
"net/http"
"time"
)

func main() {
router := gin.Default()
router.GET("/",func(c *gin.Context){
c.String(200,"test")
})
s:=&http.Server{
Addr: "0.0.0.0:7777",
Handler: router,
ReadTimeout: 60*time.Second,
ReadHeaderTimeout: 60*time.Second,
WriteTimeout: 60*time.Second,
MaxHeaderBytes: 1<<10,
}
s.ListenAndServe()
}

启动多个服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package main

import (
"github.com/gin-gonic/gin"
"log"
"net/http"
"time"
"golang.org/x/sys/sync/errgroup"
)

var g errgroup.Group

func server1() http.Handler{
r:=gin.New()
r.Use(gin.Recovery())
r.GET("/test1", func(c *gin.Context) {
c.JSON(200,gin.H{
"server":"1",
})
})
return r

}

func server2() http.Handler{
r:=gin.New()
r.Use(gin.Recovery())
r.GET("/test2", func(c *gin.Context) {
c.JSON(200,gin.H{
"server":"2",
})
})
return r

}

func main() {
s1:=&http.Server{
Addr: "0.0.0.0:1111",
Handler: server1(),
ReadTimeout: 60*time.Second,
WriteTimeout: 60*time.Second,
MaxHeaderBytes: 1<<10,
}
s2:=&http.Server{
Addr: "0.0.0.0:2222",
Handler: server2(),
ReadTimeout: 60*time.Second,
WriteTimeout: 60*time.Second,
MaxHeaderBytes: 1<<10,
}

g.Go(func()error{
return s1.ListenAndServe()
})

g.Go(func()error{
return s2.ListenAndServe()
})

if err:=g.Wait();err!=nil{
log.Fatalln(err.Error())
}
}

自定义路由日志格式

我们可以使用gin.DebugPrintRouteFunc来定义格式

默认的路由是这样子的

1
[GIN-debug] GET    /                         --> main.main.func1 (3 handlers)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"github.com/gin-gonic/gin"
"log"
"net/http"
)


func main() {
r := gin.Default()
gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int){
log.Printf("%v %v %v %v\n",httpMethod,absolutePath,handlerName,nuHandlers)
}

r.GET("/test", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status":"ok",
})
})
r.Run("0.0.0.0:7777")
}

设置Cookie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
"github.com/gin-gonic/gin"

)


func main() {
r := gin.Default()
r.GET("/",func(c *gin.Context){
cookie,err:=c.Cookie("GOSESSID")
if err!=nil{
c.SetCookie("GOSESSID","TestCookie",3600, "/", "localhost", false, true)
}
c.JSON(200,gin.H{
"Cookie":cookie,
})
})
r.Run("0.0.0.0:7777")
}