一. 重定向与请求转发基础解释
- 重定向和请求转发是两种常见的HTTP请求处理方式,它们都可以实现将请求从一个路径或地址转移到另一个路径或地址
- 重定向与请求转发的区别:
- 重定向是服务器端向客户端返回一个特殊的响应,告诉客户端重新发送一个新的请求到另一个路径或地址。请求转发是服务器端在内部将请求转移到另一个路径或地址,而不通知客户端。
- 重定向会改变浏览器的地址栏,显示新的路径或地址。请求转发不会改变浏览器的地址栏,显示原来的路径或地址。
- 重定向会增加一次网络请求,因为客户端需要重新发送一个新的请求。请求转发不会增加一次网络请求,因为服务器端在内部处理了请求。
- 重定向可以跨域,即可以将请求转移到不同的域名或协议。请求转发只能在同一个域名或协议下进行。
- 重定向会丢失原来请求的参数和数据。请求转发可以保留原来请求的参数和数据。
二. 重定向
gin.Context.Redirect()内部/外部重定向
- 代码示例:通过gin.Context.Redirect()支持重定向到外部其它域名,也支持充当向到当前服务的某个接口,
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/redirect", func(c *gin.Context) {
//使用Context调用Redirect()⽀持内部和外部的重定向
//重定向到外部
c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com/")
//重定向到内部
//c.Redirect(http.StatusMovedPermanently, "/内部接口/路径")
})
r.Run(":8080")
}
路由重定向
- 在我们编写gin服务时,要编写接口处理器,然后进行路由注册,在接收请求时,接口处理器执行,内部可以通过执行router下的HandleContext()将请求重定向到当前服务的其它路由上
r.GET("/test", func(c *gin.Context) {
//1.设置重定向的url到Context中
c.Request.URL.Path = "/test2"
//2.通过Router调用HandleContext(c)进行,重定向到/test2上
r.HandleContext(c)
})
r.GET("/test2", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"hello": "world"})
})
三. 请求转发
- 下方代码中定义了一个请求转发的处理函数 forwardHandler,该函数可以将请求转发到指定的URL。
- 使用了Gin框架提供的 router.Any 方法来定义路由,
- 将所有以 /forward/ 开头的请求转发到指定的URL。
- 在处理函数中使用了Go标准库中的 http 包来发送新的HTTP请求,并获取响应,通过复制请求的Header和响应的Header,以及将响应的状态码和Body写入原请求中,来实现请求转发的功能
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
// 创建一个Gin引擎
router := gin.Default()
// 定义一个请求转发的处理函数,将请求转发到指定的URL
forwardHandler := func(c *gin.Context) {
// 获取请求的URL和方法
url := c.Param("url")
method := c.Request.Method
// 创建一个新的http请求,并设置请求的URL、方法和请求体
req, err := http.NewRequest(method, url, c.Request.Body)
if err != nil {
// 如果创建请求失败,返回错误信息
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// 复制请求的Header到新请求中
for k, v := range c.Request.Header {
req.Header.Set(k, v[0])
}
// 发送新的http请求,并获取响应
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
// 如果发送请求失败,返回错误信息
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// 复制响应的Header到原请求中
for k, v := range resp.Header {
c.Writer.Header().Set(k, v[0])
}
// 将响应的状态码和Body写入原请求中
c.Status(resp.StatusCode)
c.Writer.Write([]byte(resp.Body))
}
// 定义一个路由,将所有以 /forward/ 开头的请求转发到指定的URL
router.Any("/forward/*url", forwardHandler)
// 启动服务
router.Run(":8080")
}