Gin框架---路由和重定向

路由原理

Gin框架作为一个轻量级的Web框架,其路由基本原理就是构造一个路由地址的前缀树,路由使用的是httprouter这个库。

路由参数

func main() {
	r := gin.Default()

    r.GET("/login/:username/:password", func(c *gin.Context) {
		username := c.Param("username")
		password := c.Param("password")
		c.String(http.StatusOK, "%s,%s", username, password)
	})

	r.GET("/user/:name/*age", func(c *gin.Context) {
		name := c.Param("name")
		age := c.Param("age")
		c.JSON(http.StatusOK, gin.H{
			"name": name,
			"age":  age,
		})
	})

	r.Run(":8080")
}
  1. 对于第一个路由,输入的路由参数必须要有username和password,但凡少了其中的一个,就会报错(返回404,也就是匹配不到路径)。也就是说有“ : ”的Path参数是必须要使用的路由参数。
  2. 对于第二个路由,输入的路由参数必须要有name参数,可以没有age参数,当不输入age参数时将会重定向到/user/name/路由下面。也就是说有“ * ”的Path参数不是必须的路由参数。
测试结果如下:
  1. 第一组路由:
Gin框架---路由和重定向_第1张图片 Gin框架---路由和重定向_第2张图片
  1. 第二组路由:
Gin框架---路由和重定向_第3张图片 Gin框架---路由和重定向_第4张图片

普通路由

r.GET("/index", func(c *gin.Context) {...})
r.POST("/index", func(c *gin.Context) {...})
r.PUT("/index", func(c *gin.Context) {...})
r.DELETE("/index", func(c *gin.Context) {...})
//等等

此外,还有一个可以匹配所有请求方法的Any方法如下:

r.Any("/index", func(c *gin.Context) {//TODO})

还可以为没有匹配处理函数的路由添加处理程序,默认情况下它返回404代码,下面的代码为没有匹配到路由的请求都返回404.html页面。

r.NoRoute(func(c *gin.Context) {
		c.HTML(http.StatusNotFound, "404.html", nil)
	})

路由组

将拥有共同URL前缀的路由划分为一个路由组。习惯性一对{ }包裹同组的路由,这只是为了看着清晰,本质上用不用{ }包裹,其功能上没什么区别。官方文档示例代码如下:

// 简单的路由组: v1
v1 := router.Group("/v1")
{
    v1.POST("/login", loginEndpoint)
    v1.POST("/submit", submitEndpoint)
}
// 简单的路由组: v2
v2 := router.Group("/v2")
{
    v2.POST("/login", loginEndpoint)
    v2.POST("/submit", submitEndpoint)
}

其中路由组也是支持嵌套的,示例代码如下:

shopping := r.Group("/shop")
{
    shopping.GET("/index", shop)
    // 嵌套路由组
    view := shopping.Group("view")
    view.GET("/home", view)
}

通常会将路由分组用在划分业务逻辑或划分API版本时。

重定向

状态码

3XX 状态码是关于重定向的,常见的状态码有:301,302,303,304,307 和 308。这些状态码大致可以分为三类,其中包括:

  • 永久重定向:301,308
  • 临时重定向:302,303, 307
  • 其他重定向:304

永久重定向

永久重定向:是指用户请求的资源地址已经废弃了,现在需要使用新地址来访问,并通过响应 Header 的 Location 字段将这个新的地址告知给用户。

就好比胡同口有一家我们常去的饭店,但是由于旧城改造这家店搬迁到了另一个地方。有一天我们准备去这家店吃饭,发现门口张贴告示:此店已迁移到 XXX,并附上了详细的新地址。也就是说,之后如果我还想去这家店吃饭,只能去新的地址。

在永久重定向中301和308的区别:

如果浏览器发送的是GET请求,301和308没有区别。但如果是POST请求,会有以下区别

  • 在301中,浏览器用POST请求服务器的/aaa地址,但是/aaa地址的资源已经永久废弃,服务器将请求重定向到/bbb的地址,此时原先的POST请求会变成GET请求。
  • 在308中,浏览器用POST请求服务器的/aaa地址,但是/aaa地址的资源已经永久废弃,服务器将请求重定向到/bbb的地址,此时原先的POST请求还是POST请求。

临时重定向

临时重定向:由于某些原因,导致用户请求的资源地址临时不可用,但其他某个地址是可访问的,于是就通过响应 Header 的 Location 字段将这个临时地址告知给用户。

就好比我们去一家饭店吃饭,到门口发现老板张贴告示:家里临时有事,请去附近另一个分店用餐,并附上了分店的详细地址。这样,我们就可以先临时去这家分店用餐,等之后老板回来了,我们又可以在原来这家店继续用餐。

在临时重定向中302、303和307的区别:

为什么永久重定向是两个状态码,而临时重定向却有三个状态码,这是与http协议的发展历史有很大关系。

在 http1.0 时期:

  • 文档规定:浏览器第一次请求的方法要和重定向时候的请求方法保持一致。

  • 在浏览器实现上:若用户第一次为 POST 请求,浏览器询问用户是否向新 URL 发送请求,并强制使用 GET发送第二个请求(与文档规定有所差异)。

在http1.1 时期:

​ 为了弥补 http1.0 时期文档中 302 和浏览器实现上 302 的偏差,这才逐渐补充了303和307的状态码。

现在:
  • 302:不管浏览器第一次请求的方法是什么,在重定向的时候请求方法被强制为GET方法。
  • 303:不管浏览器第一次请求的方法是什么,在重定向的时候请求方法被强制为GET方法。
  • 307:浏览器第一次请求的方法和重定向时的请求方法保持一致。

net包中关于重定向状态码的定义

	StatusMultipleChoices   = 300 // RFC 9110, 15.4.1
	StatusMovedPermanently  = 301 // RFC 9110, 15.4.2
	StatusFound             = 302 // RFC 9110, 15.4.3
	StatusSeeOther          = 303 // RFC 9110, 15.4.4
	StatusNotModified       = 304 // RFC 9110, 15.4.5
	StatusUseProxy          = 305 // RFC 9110, 15.4.6
	_                       = 306 // RFC 9110, 15.4.7 (Unused)
	StatusTemporaryRedirect = 307 // RFC 9110, 15.4.8
	StatusPermanentRedirect = 308 // RFC 9110, 15.4.9

HTTP重定向

r.GET("/test1", func(c *gin.Context) {
    c.Redirect(http.StatusMovedPermanently, "https://www.baidu.com")
})

路由重定向

r.GET("/test2", func(c *gin.Context) {
		c.Request.URL.Path = "/test3"  //在上下文中改变路由的路径
		r.HandleContext(c)             //把修改后的上下文写入到路由中
	})
	
r.GET("/test3", func(c *gin.Context) {
    c.JSON(http.StatusOK,gin.H{"msg":"This is /test3"})
})
结果如下:
Gin框架---路由和重定向_第5张图片

你可能感兴趣的:(Go语言,gin,后端,go)