Leong's blog Leong's blog
首页
  • 编程
  • 资源
  • Golang
  • 微服务
  • vue
  • 操作系统
  • 数据结构与算法
  • Linux
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Leong Y

跑起来吧
首页
  • 编程
  • 资源
  • Golang
  • 微服务
  • vue
  • 操作系统
  • 数据结构与算法
  • Linux
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • go基础

  • go常用库

  • web开发

    • gin使用笔记
      • 1、什么是gin
      • 2、安装
      • 3、Quickstart
      • 4、Restful API
      • 5、参数获取
        • 5.1、query 参数
        • 5.2、form 参数
        • 5.4、Json参数
        • 5.5、Path参数
        • 5.6、参数绑定 ⭐
      • 6、文件上传
      • 7、转发&重定向
  • Golang
  • web开发
leong
2024-06-03
目录

gin使用笔记

# gin使用笔记

# 1、什么是gin

Gin 是一个用 Go (Golang) 编写的高性能、易用的 Web 框架。它的设计目标是简洁、高效,并提供快速的开发体验

# 2、安装

go get -u github.com/gin-gonic/gin
1

# 3、Quickstart

func TestQuickStart(t *testing.T) {
	// 创建一个默认的路由引擎
	r := gin.Default()

	// GET请求,客户端访问'/ping'时,返回'pong'
	r.GET("/ping", func(ctx *gin.Context) {
		//ctx.JSON返回json数据
		// gin.H 是map[string]interface{}的缩写
		ctx.JSON(200, gin.H{
			"message": "pong",
		})
	})

	// 启动HTTP服务,默认再0.0.0.0:8080启动服务
	// r.Run()

	// 指定端口
	r.Run(":8085")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 4、Restful API

RESTful API 是一种基于 REST(Representational State Transfer)架构风格的应用程序编程接口。REST 是一种设计和开发网络应用的架构风格,同样的一个url可以搭配上不同的 HTTP 动词来表示操作。这些动词包括:

  • GET:读取资源
  • POST:创建资源
  • PUT:更新资源
  • DELETE:删除资源 以上的HTTP动词gin都支持:
func TestRestful(t *testing.T) {
	r := gin.Default()

	// GET
	r.GET("/ping", func(ctx *gin.Context) {
		ctx.JSON(200, gin.H{
			"message": "get",
		})
	})

	// POST
	r.POST("/ping", func(ctx *gin.Context) {
		ctx.JSON(200, gin.H{
			"message": "post",
		})
	})

	// PUT
	r.PUT("/ping", func(ctx *gin.Context) {
		ctx.JSON(200, gin.H{
			"message": "put",
		})
	})

	// DELETE
	r.DELETE("/ping", func(ctx *gin.Context) {
		ctx.JSON(200, gin.H{
			"message": "del",
		})
	})

	r.Run(":8085")
}
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

TODO

遵循rest风格的好处坏处

# 5、参数获取

# 5.1、query 参数

query是指附加再URL末尾的键值对,以(?)开始,每个参数以键值对的形式出现,键和值之间用等号(=)分隔,不同的参数之间用与号(&)分隔

http://example.com/search?q=golang&sort=asc&page=2
1

在这个 URL 中,q=golang、sort=asc 和 page=2 都是查询参数。q、sort 和 page 是参数的键,对应的 golang、asc 和 2 是这些键的值。

func TestQueryParam(t *testing.T) {
	r := gin.Default()

	// Query:如果参数不存在则返回空字符串
	r.GET("/search/query", func(c *gin.Context) {
		query := c.Query("query")
		c.JSON(200, gin.H{
			"query": query,
		})
	})

	// DefaultQuery:允许指定一个默认值,如果参数不存在则返回默认值
	r.GET("/search/default/query", func(c *gin.Context) {
		query := c.DefaultQuery("query", "default")
		c.JSON(200, gin.H{
			"query": query,
		})
	})

	// GetQuery:除了参数值,多返回一个布尔值,指示参数是否存在
	r.GET("/search/get/query", func(c *gin.Context) {
		query, exists := c.GetQuery("query")
		if !exists {
			query = "default"
		}
		c.JSON(200, gin.H{
			"query": query,
		})
	})

	// QueryMap:获取多个键值对
	// http://xxx?filters[name]=John&filters[age]=30
	r.GET("/search/query/map", func(c *gin.Context) {
		filters := c.QueryMap("filters")
		c.JSON(200, gin.H{
			"filters": filters,
		})
	})

	// QueryArray 返回多个相同键的值
	// http://xxx?tag=go&tag=gin
	r.GET("/search/query/array", func(c *gin.Context) {
		tags := c.QueryArray("tag")
		c.JSON(200, gin.H{
			"tags": tags,
		})
	})

	// 获取所有参数
	r.GET("/search/all", func(c *gin.Context) {
		// 获取所有查询参数
		queryParams := c.Request.URL.Query()

		// 将查询参数转换为 map[string]string
		params := make(map[string]string)
		for key, values := range queryParams {
			if len(values) > 0 {
				params[key] = values[0]
			}
		}
		c.JSON(200, params)
	})
	r.Run(":8085")
}
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

PS:

  • filters:
{
    "filters": {
        "age": "30",
        "name": "John"
    }
}
1
2
3
4
5
6
  • tags:
{
    "tags": ["go", "gin"]
}
1
2
3

# 5.2、form 参数

PostForm:获取表单参数

func TestFormParam(t *testing.T) {
	r := gin.Default()

	// PostForm:获取表单参数
	r.POST("/form", func(c *gin.Context) {
		name := c.PostForm("name")
		age := c.PostForm("age")
		c.JSON(200, gin.H{
			"name": name,
			"age":  age,
		})
	})

	// DefaultPostForm:允许指定一个默认值,如果参数不存在则返回默认值
	r.POST("/form/default", func(c *gin.Context) {
		name := c.DefaultPostForm("name", "anonymous")
		age := c.DefaultPostForm("age", "0")
		c.JSON(200, gin.H{
			"name": name,
			"age":  age,
		})
	})

	// GetPostForm:除了参数值,多返回一个布尔值,指示参数是否存在
	r.POST("/form/get", func(c *gin.Context) {
		name, nameExists := c.GetPostForm("name")
		age, ageExists := c.GetPostForm("age")

		if !nameExists {
			name = "anonymous"
		}
		if !ageExists {
			age = "0"
		}

		c.JSON(200, gin.H{
			"name": name,
			"age":  age,
		})
	})

	// PostFormMap:获取多个键值对
	// http://xxx?filters[name]=John&filters[age]=30
	r.POST("/form/map", func(c *gin.Context) {
		user := c.PostFormMap("user")
		c.JSON(200, gin.H{
			"user": user,
		})
	})

	// PostFormArray 返回多个相同键的值
	// http://xxx?tag=go&tag=gin
	r.POST("/form", func(c *gin.Context) {
		tags := c.PostFormArray("tag")
		c.JSON(200, gin.H{
			"tags": tags,
		})
	})
	r.Run(":8085")
}
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

# 5.4、Json参数

PS:一般都是用绑定BindJSON(下面会提到)去获取,但也提供了GetRawData方式

func TestJsonParam(t *testing.T) {
	r := gin.Default()

	r.POST("/json", func(c *gin.Context) {
		b, _ := c.GetRawData()

		var m map[string]interface{}

		// 反序列化
		json.Unmarshal(b, &m)

		c.JSON(200, m)
	})

	r.Run(":8085")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 5.5、Path参数

func TestPathParam(t *testing.T) {
	r := gin.Default()

	// Param获取
	r.GET("/user/:name", func(c *gin.Context) {
		name := c.Param("name")
		c.JSON(200, gin.H{
			"name": name,
		})
	})

	// MustGet获取(如果参数不存在,将会引发panic)
	r.GET("/user/:id", func(c *gin.Context) {
		id := c.MustGet("id").(string)
		c.JSON(200, gin.H{
			"id": id,
		})
	})

	r.Run(":8085")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 5.6、参数绑定 ⭐

gin提供了灵活的bind解析参数的方法供你选择

解析错误回在header中写一个400的状态码

	//内部根据Content-Type去解析
	c.Bind(obj interface{})
	//内部替你传递了一个binding.JSON,对象去解析
	c.BindJSON(obj interface{})
	//解析哪一种绑定的类型,根据你的选择
	c.BindWith(obj interface{}, b binding.Binding)

1
2
3
4
5
6
7

解析错误直接返回,至于要给客户端返回什么错误状态码有你决定

	//内部根据Content-Type去解析
	c.ShouldBind(obj interface{})
	//内部替你传递了一个binding.JSON,对象去解析
	c.ShouldBindJSON(obj interface{})
	//解析哪一种绑定的类型,根据你的选择
	c.ShouldBindWith(obj interface{}, b binding.Binding)

1
2
3
4
5
6
7

例子:

func TestBindParam(t *testing.T) {
	r := gin.Default()

	r.POST("/login", func(c *gin.Context) {
		var form LoginForm
		// 使用 ShouldBind 绑定数据
		if err := c.ShouldBind(&form); err != nil {
			c.JSON(500, gin.H{"error": err.Error()})
			return
		}

		c.JSON(http.StatusOK, gin.H{
			"username": form.Username,
			"password": form.Password,
		})
	})

	r.Run(":8085")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 6、文件上传

func TestFileUpload(t *testing.T) {
	r := gin.Default()

	// 处理multipart forms提交文件时默认的内存限制是32 MiB
	// 可以通过下面的方式修改
	// router.MaxMultipartMemory = 8 << 20  // 8 MiB

	// 单个文件
	r.POST("/upload", func(c *gin.Context) {
		file, err := c.FormFile("f1")
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{
				"message": err.Error(),
			})
			return
		}
		t.Log(file.Filename)
		dst := fmt.Sprintf("./upload/%s", file.Filename)
		// 上传文件到指定的目录
		c.SaveUploadedFile(file, dst)
		c.JSON(http.StatusOK, gin.H{
			"message": fmt.Sprintf("'%s' uploaded!", file.Filename),
		})
	})

	// 多个文件
	r.POST("/uploads", func(c *gin.Context) {
		// Multipart form
		form, _ := c.MultipartForm()
		files := form.File["file"]

		for index, file := range files {
			t.Log(file.Filename)
			dst := fmt.Sprintf("./uploads/%s_%d", file.Filename, index)
			// 上传文件到指定的目录
			c.SaveUploadedFile(file, dst)
		}
		c.JSON(http.StatusOK, gin.H{
			"message": fmt.Sprintf("%d files uploaded!", len(files)),
		})
	})

	r.Run(":8085")
}

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

# 7、转发&重定向

func TestForward_Redirect(t *testing.T) {
	r := gin.Default()

	// 转发
	r.GET("/forward", func(c *gin.Context) {
		// 发起一个新的 HTTP GET 请求,转发给百度
		resp, err := http.Get("http://baidu.com")
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
		defer resp.Body.Close()

		// 读取响应体
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}

		// 将响应体返回给客户端
		c.Data(resp.StatusCode, resp.Header.Get("Content-Type"), body)
	})

	// URL重定向
	r.GET("/redirect", func(c *gin.Context) {
		// 使用 302 临时重定向到另一个 URL
		c.Redirect(http.StatusFound, "http://baidu.com")
	})

	r.GET("/permanent_redirect", func(c *gin.Context) {
		// 使用 301 永久重定向到另一个 URL
		c.Redirect(http.StatusMovedPermanently, "http://baidu.com")
	})

	// 路由重定向
	// HandleContext 重新进入已重写的上下文。可以通过将 c.Request.URL.Path 设置为新目标,然后再次执行
	r.GET("/redirect1", func(c *gin.Context) {
		// 指定重定向的URL
		c.Request.URL.Path = "/redirect2"
		r.HandleContext(c)
	})
	r.GET("/redirect2", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"hello": "world"})
	})

	r.Run(":8085")
}
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
#web
上次更新: 2024/07/08, 18:19:51
Gorm学习

← Gorm学习

最近更新
01
vue3快速上手
07-31
02
程序从加载到运行的过程
07-08
03
进程、线程、协程
07-08
更多文章>
Theme by Vdoing | Copyright © 2023-2024 Leong Y | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式