为何相同HTTP请求从浏览器发起会被CORS拦截,终端curl请求却能正常返回?
核心认知:CORS是浏览器的强制拦截规则,不是服务端的请求校验规则
你看到的两种请求行为差异,本质是对CORS机制的定位理解偏差:
curl请求能正常拿到谷歌页面的原因
- curl是没有内置同源安全策略的纯HTTP客户端,发请求时不会自动附带浏览器专属的跨域标识头(比如
Origin头) - 谷歌服务端收到curl的请求时,和处理任意正常HTTP请求没有区别:正常解析请求、返回200状态和完整页面内容,全程不存在拦截
- 哪怕你手动用curl伪造和浏览器完全一致的请求头发请求,服务端照样返回内容——因为服务端本身就不会因为请求的跨域来源主动拦截请求
浏览器JS请求报CORS错误的原因
- 跨域XHR/fetch请求的所有拦截逻辑,100%是浏览器端执行的,和服务端是否处理请求没有关系:
- 浏览器发跨域请求时,会自动加上
Origin头,标记当前页面的所属域名 - 服务端收到这个请求之后,和处理curl请求的逻辑完全一致,正常返回了完整的200响应
- 响应到达浏览器后,浏览器会强制校验响应头中的
Access-Control-Allow-Origin字段:如果字段值和发起请求的页面域名不匹配(也不是通配符*),浏览器就会直接拦截响应内容,不让对应的JS代码读取,同时抛出CORS错误
- 浏览器发跨域请求时,会自动加上
- 你在JS里手动设置那几个
Access-Control-*头完全无效的原因是:这些头本身是服务端返回给浏览器的响应头,不是客户端发请求时可以随意设置的请求头。你在JS里设置这些头的操作,要么会被浏览器提前拦截不让发送,就算请求真的发出去了,服务端也不会把请求携带的这些头当成自己的响应头返回,自然过不了浏览器的校验。
这套机制的设计目的
CORS从设计之初就不是为了帮服务端拦截非法请求,而是给浏览器加一道安全防线:防止恶意网站的JS脚本,在用户已登录其他网站的状态下,偷偷携带用户的Cookie发起跨域请求、窃取其他网站的响应内容。
- 这套规则的所有校验环节都在浏览器侧执行,只要是没有内置这套校验逻辑的客户端(比如curl、爬虫、服务端发起的HTTP请求),CORS规则就完全不会生效。
- 也正因为如此,哪怕浏览器端JS被CORS拦截,用抓包工具也能看到:谷歌的服务端其实已经把完整的响应内容发回给浏览器了,只是浏览器不允许JS读取而已。
内容的提问来源于stack exchange,提问作者Crunkmastaflexx
相关产品推荐
相关产品推荐

