跨域中间件通俗理解
import ("github.com/gin-gonic/gin""net/http"
)// Cors 跨域处理
func Cors() gin.HandlerFunc {return func(c *gin.Context) {method := c.Request.Methodc.Header("Access-Control-Allow-Origin", "*")c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token")c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")c.Header("Access-Control-Allow-Credentials", "true")// 放行所有OPTIONS方法if method == "OPTIONS" {c.AbortWithStatus(http.StatusNoContent)}// 处理请求c.Next()}
}
场景:小明家和保安大叔
想象一下:
- 你的后端服务器:就是 小明家。
- 你的前端应用:是一个住在隔壁小区的 快递员。
- 浏览器(同源策略):是小明家小区门口非常负责任的 保安大叔。
正常情况(同源)
如果小明自己点外卖,外卖员是小明小区的(比如小区里的便利店),保安大叔一看是自己人,直接放行。这就是同源,不需要复杂的检查。
跨域情况(不同源)
现在,那个隔壁小区的快递员(前端)要给小明家送一个包裹(API 请求)。
- 快递员来到门口:快递员到达小明家小区门口,被保安大叔(浏览器)拦下。
- 保安大叔的规则(同源策略):保安大叔的规定是:“不是我们小区的,一律不准进!” 这就是浏览器的同源策略,天生就不信任外来人员。
这时,快递员(前端)就懵了,包裹送不进去。
“预检请求”(OPTIONS)
快递员很聪明,他不对保安大叔说“我要进去”,而是先问:
- 快递员(浏览器发送 OPTIONS 请求):“大叔,我不是来硬闯的。我就是想问问,我带着一个‘蓝色大包裹’(
Content-Type: application/json
),想用‘手推车’(POST
方法)送进去,你们家小明允许吗?”
这就是预检请求 (Preflight Request)。它不是真的在送东西,而是在投石问路。
Cors
中间件的作用
你的 Cors
中间件,就好比是小明提前给保安大叔写的一张“授权通知单”。这张通知单贴在了门卫室。
现在,我们来看看 middleware/cors.go
里的代码是怎么变成这张通知单的:
-
c.Header("Access-Control-Allow-Origin", "*")
- 通知单内容:“允许 所有小区 的快递员给我家送东西。”
- 通俗解释:告诉保安大叔,别管快递员是哪个小区的,都放行。
-
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
- 通知单内容:“允许快递员用 手推车(POST)、步行(GET) 或者只是 在门口问问(OPTIONS) 的方式送货。”
- 通俗解释:告诉保安大叔,快递员用这几种方式送货都是可以的。
-
c.Header("Access-Control-Allow-Headers", "...")
- 通知单内容:“允许快递员的包裹上贴有 ‘加急’(Authorization)、‘易碎’(Content-Type) 等特殊标签。”
- 通俗解释:告诉保安大叔,看到这些特殊标记的包裹,也是允许的。
-
if method == "OPTIONS" { c.AbortWithStatus(http.StatusNoContent) }
- 保安大叔的行动:当保安大叔看到快递员只是在门口问问话(
OPTIONS
请求),他会查阅墙上的“授权通知单”,然后对快递员挥挥手说:“问清楚了,没问题,你可以按你说的送了!” 然后就完事了。他不会再给小明打电话确认,因为通知单上写得很清楚了。这就直接结束了这次“询问”,效率很高。
- 保安大叔的行动:当保安大叔看到快递员只是在门口问问话(
-
c.Next()
- 保安大叔的行动:当一个真正的包裹(比如一个
POST
请求)来了,保安大叔检查完通知单,确认一切符合规定后,就会打开大门,说:“进去吧!”。然后快递员才能继续往小明家走。c.Next()
就是“打开大门”这个动作,让请求能继续前进。
- 保安大叔的行动:当一个真正的包裹(比如一个
总结一下
为什么需要 Cors
函数?
因为你家小区的保安大叔(浏览器) 太负责了,默认不让任何外人进。你必须写一张授权通知单(Cors
中间件) 贴在门卫室,清楚地告诉保安大叔,什么样的外来人员(哪个前端地址)、用什么样的方式(POST
/GET
)、携带什么样的东西(请求头),是可以放行的。
没有这张通知单,所有来自外部的请求都会被保安大叔拒之门外。有了它,跨小区的合作才能顺利进行。