Gin 路由和代理
路由
Gin 路由遵循 Restful API 接口规范,是基于 httproute 实现的
基本路由
语法如下,httpMethod 为请求类型,relativePath 为路径,handlers 为该路由响应函数列表(多个中间件加一个执行函数)
router.<httpMethod>(relativePath string, handlers ...HandlerFunc)
支持 GET、POST、PUT、PATCH、DELETE、OPTIONS 等请求类型,Any 方法匹配所有类型,Match 方法匹配指定的多个类型
func main() {
router := gin.Default()
router.GET("/login", loginEndpoint)
router.POST("/login", loginEndpoint)
router.Any("/login", loginEndpoint)
router.MatchMatch([]string{"POST","GET"}, "/login", loginEndpoint)
router.Run(":8080")
}
路径规则如下
- "/path",指定路径,只能匹配
/path
- "/:path",参数路由,可以匹配
/a
和/b
等,不能匹配/a/b
- "/*path",任意路由,可以匹配
/
、/a
和/a/b
等所有路由
路由按指定路径优先进行匹配,参数路由和任意路由在同一级不可共存
func main() {
router := gin.Default()
// 匹配/user/john但不会匹配/user/或者/user
router.GET("/user/:name", func(c *gin.Context) {
name := c.Param("name")
c.String(http.StatusOK, "Hello %s", name)
})
// 将匹配/user/john/和/user/john/send
// 如果没有其他路由匹配 /user/john,它将重定向到 /user/john/
router.GET("/user/:name/*action", func(c *gin.Context) {
name := c.Param("name")
action := c.Param("action")
message := name + " is " + action
c.String(http.StatusOK, message)
})
router.Run(":8080")
}
路由分组
func main() {
router := gin.Default()
// 简单的路由组: 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)
}
router.Run(":8080")
}
路由中间件
Gin 框架是洋葱结构的,可以同时使用多个中间件,按注册顺序执行,中间件中使用c.Next()
函数调用下一个中间件或路由响应函数,如果没有使用c.Next()
则执行完此中间件将会返回
func Logger() gin.HandlerFunc {
return func(c *gin.Context) {
t := time.Now()
// 请求前
c.Next()
// 请求后
latency := time.Since(t)
log.Print(latency)
}
}
func main() {
r := gin.New()
r.Use(Logger())
r.GET("/test", func(c *gin.Context) {
})
r.Run(":8080")
}
中间件可以给指定路由用,比如r.GET("/test", Logger, loginEndpoint)
代理
拼接真实服务器链接,使用 http 请求资源,再使用 DataFromReader 方法返回资源
const apiAddr = "https://example.com"
func Proxy(c *gin.Context) {
url, err := url.Parse(apiAddr + c.Request.URL.Path)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"err": err.Error(),
})
}
resp, err := http.DefaultClient.Do(&http.Request{
URL: url,
Method: c.Request.Method,
Body: c.Request.Body,
Header: c.Request.Header,
})
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"err": err.Error(),
})
}
defer resp.Body.Close()
c.DataFromReader(resp.StatusCode, resp.ContentLength, resp.Header.Get("Content-Type"), resp.Body, nil)
}
使用方法,注意:使用 Any 匹配所有 HTTP 类型的请求,使用/*path
匹配所有路径,可加入鉴权中间件限制代理的访问
router.Any("/:api/*path", Proxy)