问题描述
使用gin-contrib/cors想给gin的路由router添加CORS支持时, 如果只把cors中间件添加在某个group中, 会对浏览器发来的OPTIONS跨域请求返回404, 使跨域请求无法进行.
问题代码
package main
import (
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
corsMiddleWare := cors.Default()
//r.Use(corsMiddleWare) //CORS中间件加在全局路由时正常
r.POST("/cors_request", func(context *gin.Context) {
context.String(http.StatusOK, "hello chris")
return
})
group := r.Group("group")
group.Use(corsMiddleWare) //如果打算仅在group中使用, 则会使OPTIONS请求得到404响应.
group.POST("/cors_request", func(context *gin.Context) {
context.String(http.StatusOK, "hello chris")
return
})
r.Run(":8080")
}
请求情况:
- 如果自己用postman或者curl工具请求POST group/cors_request 直接支持跨域, 接口正常
- 但是浏览器会先发出预请求OPTIONS /group/cors_request, 得到响应404.
- 浏览器不会继续发出POST group/cors_request
解决方法
- 对路径安全要求不高, 可以把cors中间件加到全局即可
...
corsMiddleWare := cors.Default()
r.Use(corsMiddleWare)
...
- 手动为group路由添加OPTIONS方法, 返回204,允许浏览器继续请求.
...
group.Use(corsMiddleWare)
group.OPTIONS("/*options_support", func(context *gin.Context) {
context.AbortWithStatus(http.StatusNoContent)
return
})
...
追根究底
- 中间件存在处理顺序, 如果cors加在group上, 那么处理顺序为 路由匹配->corsMiddleWare, corsMiddleWare接管OPTIONS请求之前, router的路由匹配已经因为找不到对应路径而返回404.
- 加到router上, 处理顺序为 corsMiddleWare -> 路由匹配, corsMiddleWare 会给OPTIONS请求返回204, 否则就要手动添加OPTIONS方法.