简单总结前端遇到的跨域问题

537 阅读6分钟

前端需要了解的跨域知识

当你在项目中看到这样一句报错,就表明你遇到了跨域问题,那么什么是跨域?为什么会发生跨域?跨域有哪些解决方法?本文就来一一剖析。

image-20230412171437341

一、什么是跨域?

同源策略

在了解跨域之前,我们首先来看一下什么是浏览器的同源策略。源是指 协议-域名-端口 的组合,同源要求浏览器端与服务器端三者必须相同,只要有一个不同就不能称为同源。

⚠️注意:一个 ip 可以注册多个不同的域名,即多个域名可能会指向同一个 ip,即使这样也不符合同源策略。

image-20230411212420623

即图中 origin 的部分。

如果不满足同源策略,将会有下面三个方面的限制:

  • 限制不同源下读取 CookieLocalStorageIndexDB 等浏览器存储内容。
  • 限制不同源的脚本对 DOM 节点的读写操作,如 iframeDOM 节点的获取。
  • 限制不同源通过 AJAX 发送请求,请求的响应被浏览器拦截。

⚠️注意:请求实际上发送到服务端了,但是浏览器接收数据时被跨域报错拦截了。

但有三个标签允许跨域加载资源:

  • <img src="" />
  • <link href="" />
  • <script src="" />

为什么需要跨域

启用同源策略主要针对以下两个方面:针对接口等请求、针对 DOM 的查询。

没有同源策略的接口请求

cookie 存在的原因是为了解决 http 的无状态,让服务端知道是谁发出的这次请求。

如果访问不同源下的其他网站,那么其他网站就会拿到你的 cookie,就相当于登陆上了你的账号。

这就是著名的 CSRF 攻击,攻击者盗用了你的身份,以你的名义发送恶意请求。

可能会想 cookie 是明文存储的,如果遭遇 XSS 攻击(指攻击者在网页中嵌入脚本)不一样可以获取到 cookie,但是只要在响应头设置 httpOnly 就能使前端无法操作 cookie,设置 secure 则能保证在 https 的加密通信中传输,以防截获。

没有同源策略的 DOM 查询

如果一个钓鱼网站通过 iframe 引用了真实的网站,而这个 iframe 铺满整个浏览器,在误以为真的情况下,iframe 外层可以获取到 iframe 内的 DOM 元素,比如 input 等,就可以轻松监听账号密码的输入。

如果不防止跨域 DOM 节点的获取,很容易泄漏隐私。

二、跨域的解决方案

JSONP

JSONP 的原理是利用 <script> 标签的 src 属性允许跨域加载资源,来与服务器进行数据传输。但是 JSONP 需要后端配合才能实现最终的跨域请求。

简单来说就是将一个回调函数传入给后端,后端拿到后通过将数据拼接字符串作为参数写在回调函数中,并发送到前端,前端接收到字符串之后就会执行回调函数使用获得的字符串数据。

JSONP 的缺点如下:

  1. 只支持 GET 请求。
  2. 安全性较低,无法通过 withCredentials 属性设置 Cookie,也无法对请求头进行设置,容易被恶意利用进行 XSS 攻击。
  3. 服务端需要特殊处理,不利于后端的维护和开发。

CORS

CORS 全称是 Cross-origin resource sharing 跨域资源共享,CORS 的实现关键在于后端。

原理简单来讲为,向服务器发送请求通过携带一些头部信息询问是否可以跨域,在服务端允许的情况下,服务端会返回一些头部信息给浏览器,说明允许跨域。

服务端在响应头设置 Access-Control-Allow-Origin 就可以开启 CORS,该属性值为允许跨域请求的范围,如果为 *,则表示都可以进行跨域访问。

如果设置了 CORS,那么前端在发送请求是就会出现两种情况,分别为简单请求和复杂请求。

简单请求

如果请求满足:

  1. 使用 GETHEADPOST 方法之一。
  2. Content-Typetext/plainmultipart/form-dataapplication/x-www-form-urlencoded 之一。

则该请求就为简单请求。简单请求是在发送请求的时候,在请求头部增加一个 Origin 字段,对应值为当前请求的源的信息,当服务端收后返回响应,浏览器根据响应的 Access-Control-Allow-Origin 字段进行判断是否拦截响应。

复杂请求

不满足简单请求的条件的都为复杂请求。

复杂请求会在正式通信前,使用 OPTION 方法发起一个预检请求到服务端,判断是否在服务器的许可之内,服务器会返回如 Access-Control-Allow-Origin/Methods/Headers/Credentials 等字段,判断哪些源可以使用哪些方法和头信息还有凭证,只有得到肯定的答复,才会正式发起请求。

image-20230411225033570

node 中间件正向代理

我们可能会注意到,同源策略只是浏览器需要遵循的标准,如果是服务器向服务器发送请求,就无需遵循同源策略。

故我们可以通过代理服务器来解决跨域问题。主要有以下几个步骤:

  • 接受客户端请求 。
  • 将请求转发给服务器。
  • 拿到服务器响应数据。
  • 将响应转发给客户端。

image-20230411225542813

Nginx 反向代理

首先我们来看一下正向代理和反响代理之间的区别:

首先是正向代理

是指一个位于客户端和原始服务器之间的服务器,为了从原始服务器获取数据,客户端向代理发送一个请求并指定目标,然后代理向目标转接请求获得数据,再返回给客户端。只有客户端能使用正向代理。

image-20230412163236577

再来看一下反向代理: 指用代理服务器来接收请求,然后将请求转发给内部的服务器,内部服务器响应给代理服务器,代理服务器再响应给请求对象。

image-20230412164830058

正向代理和反向代理的区别

正向代理反向代理
代理客户端代理服务端
隐藏真实的客户端,真实客户端对服务器不可见隐藏真实的服务器,真实服务器对客户端不可见
主要用来解决访问限制的问题主要提供负载均衡(将用户的请求分发到空闲的服务器上)、安全防护、缓存等作用

其共同点为都是服务器和客户端的中间层,都可以加强内网的安全性,都可以做缓存机制,提高访问速度。

Nginx 就是我们常用的一种反向代理方式。

WebSocket

WebSocket 可以在客户端和服务端建立一条全双工通信的通道,其不属于同源策略,被有意设计为可以跨域的手段。

postMessage & onMessage

对于 iframe 跨域传递信息,我们可以通过 postMessageonMessage 来实现。

参考资料