参考自:[大家都是草台班子😂,我干了这么多年开发,能把跨域问题说清楚的人也没几个😅 - V2EX](https://www.v2ex.com/t/1056504?p=1#reply269) ## where 跨域只会出现在浏览器环境中! 跨域只会出现在浏览器环境中! 跨域只会出现在浏览器环境中! 重要的事情说三遍。 我知道为啥很多后端开发很疑惑为啥有这种问题,因为纯服务端之间应该没有这个概念。 首先解释清楚什么情况下,会被认定成跨域: 页面地址的域名是 A,但是接口请求的地址是 B。这就是跨域,跨越了不同的域 (名) 想要去请求资源。 在浏览器中会发生的现象: 浏览器会阻止给和页面地址不同的域名发请求。 这跟语言无关,这就是一个在浏览器环境下的安全策略。 - 假设你的前端应用部署在 http://pricetool.corp.qunar.com - 而你的 API 部署在 http://api.corp.qunar.com - 为了让前端应用能够访问 API,需要在 API 的控制器中配置 CORS: - 浏览器发现前端在 a.com 而要发一个请求给 b.com 的后端, - 浏览器会阻止这种行为 - 除非后端 b.com 明确表示了豁免,可以接受 a.com 的请求 - 在 spring 中,靠 `CrossOrigin` 实现 ## 怎么办 a:请把你的页面域名加入白名单。使用响应头 Access-Control-Allow-Origin 来处理。 [https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin) b:或者使用 nginx,前端请求的接口还是用网页的域名,但是用 ngxin 转发到服务端的地址去。 拓展: 其实后端的响应头是能帮助前端做不少事情的。 比如 Access-Control-Allow-Methods 这个头,能约定接口只能发 post,还是 get 比如 Access-Control-Allow-Headers,后端通常会返回很多响应头字段, 但是在浏览器环境下,为了安全,浏览器只允许 js 访问固定的几个响应头。 如果想让前端访问其它的响应头字段,就可以通过 Allow-Headers 进行配置。 比如如果你想让前端做一个下载进度条,正确的返回 Content-Length,前端就能计算下载进度。 比如 Content-Disposition,只要你声明本次请求是一个附件并正确的有文件名称,就能自动触发浏览器的文件下载,不需要前端在额外做任何事情。 ## 疑问 1:为啥开发环境都没事啊? 类似这个帖子的疑问: [https://www.v2ex.com/t/1056317](https://www.v2ex.com/t/1056317) 开发的时候前端本地页面地址是 localhost,接口地址肯定是其他的,为啥不跨域? 因为现在前端项目,开发用的脚手架通常会在本地用 node.js 启动一个 http 服务, 本来发给 B 域名的请求,会被代码改写成请求到 localhost(或者 127.0.0.1) 的 http 服务去, 然后通过 node.js 的转发进行真正的接口调用。 正如我上面说的,跨域只会存在于浏览器环境,node.js 可以给任何域名发 http 请求。 我认为这是现在的前端脚手架提供的一个极其糟糕的功能。 它把跨域这个完全由后端处理的问题默默的在开发环境处理掉了,并且还附加了接口地址改写的各种功能 导致前后端都稀里糊涂的。跨域问题就应该在开发环境处理掉。 ## 疑问 2 既然开发环境前端都可以自行处理跨域,那我打包部署的时候部署一样应该可以啊? 类似这个帖子的疑问: [https://www.v2ex.com/t/1056317](https://www.v2ex.com/t/1056317) 因为普通的前端构建打包后,只有前端的代码。不会包含任何 node.js 的代码。 现在的前端项目就是真真正正的一堆静态资源。不像以前的 jsp 需要服务器跑。 只需要一个 ngxin 来提供静态文件访问的能力就行。 ## 疑问 3:不对啊,我在自己网站可以随便链接好多别的域名的涩图,不也跨域了? 对图片这种资源限制没那么严格,其它类型资源也有这个问题。 现在是可以通过 CSP 策略来告诉浏览器,我只能从什么域名加载什么样的资源。 [https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy) ## 疑问 4:为啥我见过浏览器发 option 请求? 正如上面说的,这是浏览器的安全策略。但是有一个问题,如果浏览器从来就没请求过 B 域名, 它怎么知道页面当前域名在不在 B 域名的白名单中呢? 所以就有 option 请求,一个不带任何数据的请求,就是问一下 B 域名的服务器,你给我了啥权限。 个人结尾来点感想: 我不是嘲讽说谁谁菜不懂这个技术点,我干了这么久开发,深知每个人都有自己的局限性。 比如我上面的解释就是我当前的理解,如果有错误那就是我的局限性。 看了我上面解释的一大堆,猜到我本职是后端开发还是前端开发了吗? 如果我上面有任何错误欢迎指正批评。 我知道 V2EX 这里经常嘲讽前端是娱乐圈,但是前端开发作为客户端开发的一个分支, 在加上由于 electron 这个牛逼项目的普及,大家使用的客户端软件,事实上很多都已经是用前端页面来做了。 比如 vscode 就是。包括各种小程序等等,本质都是 web 端的扩展。 只要有技术力还是能做出很棒的软件的。(我之前听说马斯克的很多项目 UI 层都是 electron,上太空都行) 第 1 条附言  ·  5 天前 感谢#62 @[DOLLOR](https://www.v2ex.com/member/DOLLOR) 和 #144 @[bugfan](https://www.v2ex.com/member/bugfan) 的补充。 如果未能正确设置跨域,那么接口会被浏览器正常请求,后端会正常收到。 但是返回的时候会被浏览器强行拦截。 感谢#105 @[Liam1997](https://www.v2ex.com/member/Liam1997) 的补充。 浏览器地址栏的请求是不会有跨域问题的🤣 非常经典的问题。