路由重定向

重定向告诉浏览器去访问另一个 URL。HTTP 定义了多种重定向状态码,Gin 都支持。

基本重定向

使用 Redirect() 方法:

r.GET("/old-path", func(c *gin.Context) {
    c.Redirect(301, "/new-path")
})

访问 /old-path 会重定向到 /new-path

重定向状态码

301 Moved Permanently

永久重定向,告诉浏览器和搜索引擎这个 URL 已经永久移动:

r.GET("/old-page", func(c *gin.Context) {
    c.Redirect(301, "/new-page")
})

302 Found

临时重定向,表示资源暂时移动:

r.GET("/temp-page", func(c *gin.Context) {
    c.Redirect(302, "/actual-page")
})

307 Temporary Redirect

类似于 302,但更明确地表示是临时重定向:

r.GET("/temp", func(c *gin.Context) {
    c.Redirect(307, "/destination")
})

308 Permanent Redirect

类似于 301,但更明确地表示是永久重定向:

r.GET("/permanent", func(c *gin.Context) {
    c.Redirect(308, "/final-destination")
})

外部 URL 重定向

r.GET("/google", func(c *gin.Context) {
    c.Redirect(302, "https://www.google.com")
})

r.GET("/blog", func(c *gin.Context) {
    c.Redirect(301, "https://blog.example.com")
})

带查询参数的重定向

r.GET("/search", func(c *gin.Context) {
    query := c.Query("q")
    target := "/results?q=" + query
    c.Redirect(302, target)
})

HTTPS 重定向

r.GET("/secure", func(c *gin.Context) {
    c.Redirect(301, "https://example.com/secure")
})

域名重定向

r.GET("/old-site", func(c *gin.Context) {
    c.Redirect(301, "https://newsite.com")
})

完整示例

package main

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

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

    setupRedirects(r)

    r.GET("/new-path", func(c *gin.Context) {
        c.JSON(200, gin.H{"message":: "这是新路径"})
    })

    r.GET("/actual-page", func(c *gin.Context) {
        c.JSON(200, gin.H{"message": "这是实际页面"})
    })

    r.Run(":8080")
}

func setupRedirects(r *gin.Engine) {
    r.GET("/old-path", func(c *gin.Context) {
        c.Redirect(http.StatusMovedPermanently, "/new-path")
    })

    r.GET("/temp-page", func(c *gin.Context) {
        c.Redirect(http.StatusFound, "/actual-page")
    })

    r.GET("/legacy-api", func(c *gin.Context) {
        c.Redirect(http.StatusMovedPermanently, "/api/v1")
    })

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

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

重定向循环

要避免重定向循环:

r.GET("/a", func(c *gin.Context) {
    c.Redirect(302, "/b")
})

r.GET("/b", func(c *gin.Context) {
    c.Redirect(302, "/c")
})

r.GET("/c", func(c *gin.Context) {
    c.Redirect(302, "/a")
})

这会导致浏览器报错。正确的做法是:

r.GET("/a", func(c *gin.Context) {
    c.Redirect(302, "/b")
})

r.GET("/b", func(c *gin.Context) {
    c.Redirect(302, "/final")
})

r.GET("/final", func(c *gin.Context) {
    c.JSON(200, gin.H{"message": "最终页面"})
})

条件重定向

根据条件决定是否重定向:

r.GET("/content", func(c *gin.Context) {
    version := c.Query("version")
    
    if version == "v1" {
        c.Redirect(302, "/content/v1")
    } else if version == "v2" {
        c.Redirect(302, "/content/v2")
    } else {
        c.JSON(200, gin.H{"message": "默认内容"})
    }
})

小结

这一章学习了:

  • 使用 Redirect() 进行重定向
  • 不同重定向状态码的含义
  • 内部和外部 URL 重定向
  • 避免重定向循环