最近在学习 Golang + Gin + Vue.js 的项目,在处理 CORS 跨域问题上发现了个不算坑的坑。
1
2
3
4
5
6
7
| func New() *gin.Engine {
router := gin.Default()
registerPostApis(router)
registerUserApis(router)
router.Use(cors.Default())
return router
}
|
这个是我一开始写的,然后发现不管是用 Gin 官方的 CORS 中间件,还是自己写一个 CORS 中间件,在前端 Vue.js 用 axios 调用的时候,会出现
cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote
resource at http://127.0.0.1:8081/user/login. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
但这不应该,我都有设置好 Access-Control-Allow-Origin
, Access-Control-Allow-Header
等 Headers
通过抓包也能看到 response 里面没有这些信息
然后,我把中间件放到了注册路由的前面,即
1
2
3
4
5
6
7
| func New() *gin.Engine {
router := gin.Default()
router.Use(cors.Default())
registerPostApis(router)
registerUserApis(router)
return router
}
|
一切都顺畅了,不会出现跨域的问题了。
那么,是为什么呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery())
return engine
}
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
engine.RouterGroup.Use(middleware...)
engine.rebuild404Handlers()
engine.rebuild405Handlers()
return engine
}
func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
group.Handlers = append(group.Handlers, middleware...)
return group.returnObj()
}
|
可以看到,调用 engine.Use()
的时候,是调用了engine.RouterGroup.Use()
,然后将中间件加入到了 group.Handlers
里。
而在注册路由的时候,用到了 engine.Group()
即使不用 Group()
,直接用 engine.GET("/URL")
也是一样的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
return &RouterGroup{
Handlers: group.combineHandlers(handlers),
basePath: group.calculateAbsolutePath(relativePath),
engine: group.engine,
}
}
func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain {
finalSize := len(group.Handlers) + len(handlers)
if finalSize >= int(abortIndex) {
panic("too many handlers")
}
mergedHandlers := make(HandlersChain, finalSize)
copy(mergedHandlers, group.Handlers)
copy(mergedHandlers[len(group.Handlers):], handlers)
return mergedHandlers
}
|
对于这个路由组的中间件,是把 engine 的中间件复制一份给了 mergedHandlers,
也就是把已有的中间件和新增的中间件和在一起使用了
也就是说,如果在注册路由之后,新增了一个中间件,那这个中间件不会对已经注册的路由产生效果。