V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
shadowyue
V2EX  ›  程序员

大家都是草台班子😂,我干了这么多年开发,能把跨域问题说清楚的人也没几个😅

  shadowyue · 143 天前 · 34831 次点击
这是一个创建于 143 天前的主题,其中的信息可能已经有所发展或是发生改变。
跨域只会出现在浏览器环境中!
跨域只会出现在浏览器环境中!
跨域只会出现在浏览器环境中!
重要的事情说三遍。
我知道为啥很多后端开发很疑惑为啥有这种问题,因为纯服务端之间应该没有这个概念。

首先解释清楚什么情况下,会被认定成跨域:
页面地址的域名是 A ,但是接口请求的地址是 B 。这就是跨域,跨越了不同的域(名)想要去请求资源。

在浏览器中会发生的现象:
浏览器会阻止给和页面地址不同的域名发请求。
这跟语言无关,这就是一个在浏览器环境下的安全策略。

怎么办:
请把你的页面域名加入白名单。使用响应头 Access-Control-Allow-Origin 来处理。
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
或者使用 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
开发的时候前端本地页面地址是 localhost ,接口地址肯定是其他的,为啥不跨域?
因为现在前端项目,开发用的脚手架通常会在本地用 node.js 启动一个 http 服务,
本来发给 B 域名的请求,会被代码改写成请求到 localhost(或者 127.0.0.1)的 http 服务去,
然后通过 node.js 的转发进行真正的接口调用。
正如我上面说的,跨域只会存在于浏览器环境,node.js 可以给任何域名发 http 请求。

我认为这是现在的前端脚手架提供的一个极其糟糕的功能。
它把跨域这个完全由后端处理的问题默默的在开发环境处理掉了,并且还附加了接口地址改写的各种功能
导致前后端都稀里糊涂的。跨域问题就应该在开发环境处理掉。

疑问 2:
既然开发环境前端都可以自行处理跨域,那我打包部署的时候部署一样应该可以啊?
类似这个帖子的疑问: 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

疑问 4:为啥我见过浏览器发 option 请求?
正如上面说的,这是浏览器的安全策略。但是有一个问题,如果浏览器从来就没请求过 B 域名,
它怎么知道页面当前域名在不在 B 域名的白名单中呢?
所以就有 option 请求,一个不带任何数据的请求,就是问一下 B 域名的服务器,你给我了啥权限。


个人结尾来点感想:
我不是嘲讽说谁谁菜不懂这个技术点,我干了这么久开发,深知每个人都有自己的局限性。
比如我上面的解释就是我当前的理解,如果有错误那就是我的局限性。
看了我上面解释的一大堆,猜到我本职是后端开发还是前端开发了吗?
如果我上面有任何错误欢迎指正批评。
我知道 V2EX 这里经常嘲讽前端是娱乐圈,但是前端开发作为客户端开发的一个分支,
在加上由于 electron 这个牛逼项目的普及,大家使用的客户端软件,事实上很多都已经是用前端页面来做了。
比如 vscode 就是。包括各种小程序等等,本质都是 web 端的扩展。
只要有技术力还是能做出很棒的软件的。(我之前听说马斯克的很多项目 UI 层都是 electron ,上太空都行)
第 1 条附言  ·  143 天前
感谢#62 @DOLLOR 和 #144 @bugfan 的补充。
如果未能正确设置跨域,那么接口会被浏览器正常请求,后端会正常收到。
但是返回的时候会被浏览器强行拦截。

感谢#105 @Liam1997 的补充。
浏览器地址栏的请求是不会有跨域问题的🤣 非常经典的问题。
272 条回复    2024-07-18 21:45:36 +08:00
1  2  3  
ZeroDu
    201
ZeroDu  
   142 天前
@NessajCN #150 大神,建议新开贴来给大家普及。
ZeroDu
    202
ZeroDu  
   142 天前
@Nosub #84 你这就是在误导人。你说的这些那都是一个思路开代理服务器呗。你讲这些怼 op 只能显得你不懂了
cz5424
    203
cz5424  
   142 天前   ❤️ 1
全干工程师觉得,楼主讲的比较清晰了,哈哈哈
ZeroDu
    204
ZeroDu  
   142 天前
@watzds #197 这让我想起了,曾经有人认为只有 {... } 这样的才是 json 。
oyps
    205
oyps  
   142 天前
@NessajCN OP 的帖子应该还是为了方便新手理解吧,虽然不算特别严谨,但是也没说错。你当然可以从更本质的 credentials 去理解,但是 credentials 只是出发点,之后的东西也是要认真学习的。看大佬这么自信,期待你单独讲讲跨域,让我等膜拜一下。
revalue
    206
revalue  
   142 天前 via Android
后端不懂就是因为面试官觉得不重要所以不问。盲区取决于面试题
11232as
    207
11232as  
   142 天前
后端选手,最早接触跨域还是刚入行时老板提醒 XSS 攻击了解到的...
zhangk23
    208
zhangk23  
   142 天前   ❤️ 1
好文!
charlie21
    209
charlie21  
   142 天前   ❤️ 1
这方面的知识,如果很难做出一个最小 demo 去复现 / 展示问题 / 展示情况 / 做实验 lab ,那么
对于那些号召动手优于动嘴的人们而言
是很难真正解决 / 试验成功的
CFCL
    210
CFCL  
   142 天前   ❤️ 1
挺好的,有争论
jydeng
    211
jydeng  
   142 天前   ❤️ 1
😆 完全正确,是浏览器的限制。
3country
    212
3country  
   142 天前   ❤️ 1
受教了
MrDarnell
    213
MrDarnell  
   142 天前
看了评论区的大多数人的回复,其实 90%还是没搞懂跨域这玩意,跨域实际上是浏览器的安全机制,Access-Control-Allow-Origin 源的设置是提供服务方(可以是 http 服务也可以是代理服务,之所以前端一直提代理,因为在前端开发测试的过程默认会启动一个 http 服务,这个期间是可以使用代理来规避同源问题的)在响应头里告诉浏览器 你允许那些来源的域可访问,如果浏览器认为当前发起域和访问不符,且响应头里的允许源未命中,则浏览器会自动中断 http 并报错,当然最有效的方式就是通过 http 代理服务器进行同源代理,这样最有效,响应头是第三方对接的玩法!比如说 oss 的图片请求的安全域等,需要手动录入的
MrDarnell
    214
MrDarnell  
   142 天前
@Gotchaaa 小程序本是就实现了安全域的机制,这个需要在微信后台录入并验证,这个和浏览器的同源策略不谋而合,实际上是有跨域机制的,玩法有区别
Gotchaaa
    215
Gotchaaa  
   142 天前
@MrDarnell 是这样没错,但是你在开发者工具中就能发现,当你打开忽略安全域名,也不会有有跨域的问题
2b8WkA50T2xXU9mq
    216
2b8WkA50T2xXU9mq  
   142 天前
nextjs 完美解决跨域问题
MrDarnell
    217
MrDarnell  
   142 天前
@Gotchaaa 正式服你也可以忽略安全域,这个就没必要展开讨论了!
adzchao
    218
adzchao  
   142 天前   ❤️ 1
mark !说的不错
sinno933
    219
sinno933  
   142 天前
@NessajCN OP 讲的是跨域请求被浏览器 block 的问题,你讲的是解决了 block 的问题后能否携带 cookies 的问题,其实都没有错。
whoami9894
    220
whoami9894  
   142 天前   ❤️ 1
搞不懂这种简单问题的去读《 Web 之困》,看完你会理解为什么浏览器要限制跨域,为什么有同源策略,更进一步理解现有 Web 模型存在哪些设计硬伤,跨域只是对现有 Web 模型打的补丁

---

第二部分 浏览器安全特性
第 9 章 内容隔离逻辑 / 134
9.1   dom 的同源策略 / 135
9.1.1   document.domain / 136
9.1.2   postmessage(...) / 137
9.1.3  与浏览器身份验证的交互 / 138
9.2   xmlhttprequest 的同源策略 / 139
9.3   web storage 的同源策略 / 141
9.4   cookies 的安全策略 / 142
9.4.1   cookie 对同源策略的影响 / 144
9.4.2  域名限制带来的问题 / 145
9.4.3   localhost 带来的非一般风险 / 145
9.4.4   cookie 与“合法”dns 劫持 / 146
9.5  插件的安全规则 / 147
9.5.1   adobe flash / 148
9.5.2   microsoft silverlight / 151
9.5.3   java / 151
9.6  如何处理格式含糊或意想不到的源信息 / 152
9.6.1   ip 地址 / 153
9.6.2  主机名里有额外的点号 / 153
9.6.3  不完整的主机名 / 153
9.6.4  本地文件 / 154
9.6.5  伪 url / 155
9.6.6  浏览器扩展和用户界面 / 155
9.7  源的其他应用 / 156
9.8  安全工程速查表 / 157
第 10 章 源的继承 / 158
10.1   about:blank 页面的源继承 / 158
10.2   data: url 的继承 / 160
10.3   javascript:和 vbscript: url 对源的继承 / 162
10.4  关于受限伪 url 的一些补充 / 163
10.5  安全工程速查表 / 164
第 11 章 同源策略之外的世界 / 165
11.1  窗口和框架的交互 / 166
11.1.1  改变现有页面的地址 / 166
11.1.2  不请自来的框架 / 170
11.2  跨域内容包含 / 172
11.3  与隐私相关的副作用 / 175
11.4  其他的同源漏洞和应用 / 177
11.5  安全工程速查表 / 178
第 12 章 其他的安全边界 / 179
12.1  跳转到敏感协议 / 179
12.2  访问内部网络 / 180
12.3  禁用的端口 / 182
12.4  对第三方 cookie 的限制 / 184
12.5  安全工程速查表 / 186
8153
    221
8153  
   142 天前   ❤️ 1
一个全栈说一嘴:OP 说的大部分没错,但是个人建议是前端解决,原因如下:
1.跨域本身就是限制的前端网页,你要明白为啥要限制浏览器。
2.后端解决跨域没那么简单的,尤其是涉及 cookie ,而且 chrome 有越来越严格的迹象,不是一个*就能解决的(老后端都踩过坑),然后生产环境再改回来?
3.前端一个 nginx 转发,轻松解决啊,太简单了。
whoami9894
    222
whoami9894  
   142 天前   ❤️ 1
@encro #58
我也讲点核心的,你的理解都是错的

1. script 和 img 标签不受同源策略限制
2. 即使通过 XHR 请求图片,对于非复杂请求,请求会正常发到你的服务器,只是浏览器会 block 读取跨域请求的 response ,你的流量一样会被刷爆
shadowyue
    223
shadowyue  
OP
   142 天前   ❤️ 1
#221 诶😮,在 nginx 处理这个问题你是归类到前端吗?上面也有些讨论,觉得 ngxin 应该是归属后端或者运维。
因为一般能去改 ngxin 配置的都是运维或者后端,公司甚至不会给前端登录服务器的权限。
不过这也不重要,能正确处理问题就好。感谢你的回复。
shadowyue
    224
shadowyue  
OP
   142 天前
#221 @8153
续#223 不过可能真的是不同团队分工不一样。我现在公司的情况是,明面上 ngxin 配置都是运维负责。
但是只有新项目第一次上线的时候来处理。后续的维护都是交给负责项目的后端。
但是实际上我自己又申请了服务器的权限,最终是我自己再负责配置🤣
8153
    225
8153  
   142 天前   ❤️ 1
@shadowyue
1.前后端分离的话,前端应该是有专门的服务器,配置不高就行啊...
2.我不了解让前端 ssh vi wq 的难度是多少...
3.如果大家接受 nginx 转发解决跨域的话,无论前端还是后端应该都是很乐意的吧
BuffDog
    226
BuffDog  
   142 天前   ❤️ 1
作为一个全栈,发现有些后端确实不知道这个问题,当然跟他们也没关系,毕竟这个是浏览器机制
isyes
    227
isyes  
   142 天前
这就是一种 PUA ,只有打工人才需要知道这么多技能,老板是不需要这么多技能。
shanhaisilu
    228
shanhaisilu  
   142 天前
跨域的出现和前端处理,这个文章描述的还行
https://juejin.cn/post/7122473590238216229
Gotchaaa
    229
Gotchaaa  
   142 天前
@MrDarnell 不行,我就要讨论。

想讨教一下,正式服如何忽略?

我只是想说小程序没有跨域,只是通过安全域名实现了和跨域一样的功能,通过在开发者工具中忽略安全域名就能验证小程序没有跨域。(另外体验版也能够通过打开调试工具来忽略)。

不知道哪里引起你的误解了。
IanHo
    230
IanHo  
   142 天前   ❤️ 1
点赞。
ccqc
    231
ccqc  
   142 天前
前端天天扯这个,我现在都是直接默认加上*,反正也没有要求
encro
    232
encro  
   142 天前
@whoami9894


你是对的。

通常只有 waf 限制 reffer 才能真正屏蔽访问流量。

我这个简化做得不好。。。
yyyyyyh
    233
yyyyyyh  
   142 天前   ❤️ 1
没想到 .... 这个帖子能扯这么多 这下真是草台班子了
ephemeral13
    234
ephemeral13  
   142 天前   ❤️ 1
牛!
Iakihsoug
    235
Iakihsoug  
   142 天前
完全不认同,说实话我觉得老哥想得浅了点,跨域并不是一个需要解决的问题
与其颐气指使指责后端没有处理跨域,倒不如想想
1 为什么会有同源限制
2 为什么前端要做 proxy 来避免
3 为什么跨域不限制某些资源
ifbluethen
    236
ifbluethen  
   142 天前 via iPhone
前端面试的时候总是被问这个问题,有的回答出来了,还非得让你回答前端如何解决跨域问题
bello123
    237
bello123  
   142 天前
@Iakihsoug 所以...为什么
leonhao
    238
leonhao  
   142 天前   ❤️ 1
跨域不光是域名,还有协议和端口
Iakihsoug
    239
Iakihsoug  
   142 天前
@bello123 说跨域是个问题 然后要求后端忽略同源策略,在我看来就跟连不上服务器,要求服务器关掉防火墙一样。
相反后端从来不会指责服务器开了防火墙,而是乖乖使用堡垒机。
生产环境 domain 请求 domain/api 并没有什么问题
开发环境 proxy 的作用是让浏览器认为 localhost 是在请求 localhost/api
如果 OP 想要 domainA 请求 domainB/api 正确的途径是 domainA -> domainA/api -> domainB/api
而不是让 domainB 放开口子
holdeer
    240
holdeer  
   142 天前
用不到的东西,为什么要搞清楚
DreamyTZK
    241
DreamyTZK  
   142 天前   ❤️ 1
Iakihsoug
    242
Iakihsoug  
   142 天前   ❤️ 1
另外,我发现都没人提的一件事,开了 Access-Control-Allow-Origin: *,等你要发版的时候,你的安全检测报告会告诉你这是个高危,不修复不给上
不知道前端的同学能不能顺便帮忙请愿下取消这种流程,毕竟我没法告诉它说它不懂跨域
randomstream
    243
randomstream  
   142 天前   ❤️ 1
@shadowyue 同感,我理解的是前端(在浏览器范围内)根本处理不了跨域问题,还天天问跨域是啥是啥,不就是浏览器的限制, 要后端或其他处理
DreamyTZK
    244
DreamyTZK  
   142 天前
@Iakihsoug 正常情况下不应该设置为 * 的 。最好的做法是 谁请求 动态设置谁
SchwarzeR
    245
SchwarzeR  
   142 天前
Access-Control-Allow-Origin: * 的情况如果涉及到携带 cookies 、token 等情况会失效的,具体规则请参阅 MDN 的跨域与 CORS 部分章节

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS

省事的做法是 gateway 或者后端配置 cors 中间件请求头 Access-Control-Allow-Origin ,来什么$http 就回什么$http
安全的做法是上线后只返回对应域名 Access-Control-Allow-Origin
顺便说一下这不是八股文的内容吗不背不理解怎么找工作,好像是要问到 preflight 的有效期限的 [x
mingtdlb
    246
mingtdlb  
   142 天前
过个三五天,你可能又忘记了,不常用的东西,只会记得大概甚至只知道有这么个东西。
firefox12
    247
firefox12  
   142 天前
@encro

比如我公司的静态 js 和图片,被某大流量网站直接引用了,我流量不直接被刷爆?

是我的知识需要更新了吗? html 引用一张别人站点的静态图片 难道是不允许的? 浏览器会拒绝? 那么 cdn 的图片怎么被站点引用?
cz5424
    248
cz5424  
   141 天前
@firefox12 cdn 限制 referer 屏蔽非自身网站的请求,这个跟跨域不是一回事了
firefox12
    249
firefox12  
   141 天前
@cz5424 所以他把这个说法加到跨域这里 我也是不懂了。我的理解跨域问题,客户端的请求还是会发的,结果也会拿回去的,只是被丢弃掉而已,而且 get 操作应该没有跨域问题的吧。
Nosub
    250
Nosub  
   141 天前
@xzylzz 写了一篇给后端开发看的关于 CORS 的文章:

CORS 的实现原理以及 Spring 实战,https://nosub.net/posts/p/165
mercury233
    251
mercury233  
   141 天前   ❤️ 1
@Nosub #250
看开头就知道你没有了解 CORS 的本质。CORS 不是服务器端的需求,不是所谓防止“被未知的应用请求”。因为除了在正规浏览器正常运行的网页外,其他客户端应用都可以任意设定伪造 HTTP 头。而 CORS 基于 HTTP 头运行,可以说不考虑伪造,所以 CORS 不能实现你想象中的效果。

CORS 就是浏览器的需求,目的是在用同源策略保护用户的前提下让网站能实现一些功能。正常情况下在浏览器浏览的 a.com 里的网页通过脚本跨站访问 b.com 不会带 b.com 的 cookie ,而 b.com 设定好 CORS 之后浏览器就会允许这种访问带 cookie 。
早期有些浏览器没有严格执行同源策略,导致正常网站和恶意网站可以任意跨站。现在各大浏览器都修复了这种安全问题,正常网站想继续跨站就要在 b.com 设置 CORS 允许 a.com 访问。所以 CORS 是浏览器规定和推动的。

跨域问题只存在于浏览器,完全由浏览器负责拦截,服务器不能简单利用 CORS 防止未知客户端伪造 HTTP 头,要防止那是反爬的技术。
shadowyue
    252
shadowyue  
OP
   141 天前
#250 @Nosub
你这句话:
如果你了解了这个核心作用,你依然说跨域只存在于浏览器,完全是胡说八道。

据我所知跨域问题确实是浏览器才有的问题。服务端什么场景会出现,可以讲一下
mercury233
    253
mercury233  
   141 天前
@Nosub #250 省流:浏览器会禁止某些访问,CORS 的目的是允许这些访问。

> 我不希望我的 APIS 被未知的应用请求
所谓未知的应用只要不运行在正规浏览器,本来就不会禁止这些访问,自然和 CORS 无关。
xzylzz
    254
xzylzz  
   141 天前
@Nosub 我怀疑你是来推你个人博客的,开头就错了。你在浏览器环境之外见过跨域报错的吗...
encro
    255
encro  
   141 天前
@firefox12

是我例子没举正确。。

通常只有通过 reffer 才能真正屏蔽访问流量。
TomXx
    256
TomXx  
   141 天前
![image]( https://i.111666.best/image/WKRfSh4QQwIlGw1LwmAgWs.png)
有人知道小红书这个 allow-origin 是 0 是什么意思吗,还有为啥他们只允许 GET 和预检请求
TomXx
    257
TomXx  
   141 天前
parareptilia
    258
parareptilia  
   141 天前
在中间件设置一下 cors 不就得了?
xueyuehua
    259
xueyuehua  
   141 天前
我一直不懂为什么会有这个限制,基本上百分之九十九的应用,遇到跨域都会允许,那这个跨域不就失去它原有存在的意义了,反而还给开发带来麻烦
Chuckle
    260
Chuckle  
   141 天前
好了,再讲讲跨域携带 cookie 以及有关响应头值吧,还有 option 与简单、非简单请求的恩怨情仇,好吧默认的跨域也总比自己去写出五花八门的 csp 好(协议也是草台班子
Chuckle
    261
Chuckle  
   141 天前   ❤️ 1
为了方便,我拿 node 写后端先 cv 上这个中间件,获取请求头的 origin ,看是否在白名单域名里,再让 options 快速响应
Midnight
    262
Midnight  
   141 天前
知道了,然后呢
oyps
    263
oyps  
   141 天前   ❤️ 1
@xueyuehua 浏览器设置同源策略是非常有必要的,一般来说,服务器数量是少于客户端数量的,同源策略可以限制客户端的数量和场景都在一定的范围内,如果没有同源策略,随便一个网页都能发起请求,岂不是随时随地刷你的流量,垃圾堆里都能找出个 HTML 来发个 Ajax
leonshaw
    264
leonshaw  
   141 天前 via Android
看起来不少人只知道跨域访问现象,没理解同源策略的目的是什么。
qingfeiqf
    265
qingfeiqf  
   141 天前
那么,提个问题,如果我要实现在我的系统里面能随时配置其他系统的域名直接 iframe 到平台(有的系统已经实现单点登录),有什么需要注意的吗?或者 ta 这么做就是会因不同域名的不同情况会有各种问题,无法实现?
zzzzzzggggggg
    266
zzzzzzggggggg  
   141 天前
我一直以为这是基本功啊
fumichael
    267
fumichael  
   141 天前
当年我跟后端同事合作的时候,他表示不知道有这回事

他也是这么回复我的,为什么我请求没问题( postman 请求)

后来我自己把后端也学了…
zbinlin
    268
zbinlin  
   140 天前
大家都在说缺少 CORS http header 导致跨域问题,其实当返回的响应里有多个 'Access-Control-Allow-Origin' http header 时也是一种灾难。
shadowyue
    269
shadowyue  
OP
   139 天前
😂v2ex 收藏最多的帖子是哪个,我这个收藏量可否与之一战
imlonghao
    270
imlonghao  
   137 天前 via iPhone
@Chuckle 261 楼的代码也是草台班子,判断 Origin 是否在白名单不能用 includes 来判,我拿一个 Origin: https://undefined.example.com 就绕过了
Chuckle
    271
Chuckle  
   137 天前
@imlonghao 确实该改改,太草班了,先提取出 Origin 的域名再去对比好点
dc25b
    272
dc25b  
   135 天前
分享一篇 Dzone 的文章,我感觉基本把帖子里探讨的问题讲透彻了:
https://dzone.com/articles/do-you-really-know-cors
1  2  3  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2734 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 26ms · UTC 07:33 · PVG 15:33 · LAX 23:33 · JFK 02:33
Developed with CodeLauncher
♥ Do have faith in what you're doing.