前端跨域问题原因分析以及解决方式

前端跨域问题的解决方案

1. 造成跨域的原因

跨域是指一个域下的文档或脚本试图去请求另一个域下的资源.这里的跨域是广义的.
广义的跨域包括:

  • 资源跳转: 链接,重定向,表单提交
  • 资源嵌入: <link>,<script>,<img>,<iframe>等 DOM 标签
  • 脚本请求: javascript 发起的 Ajax 请求等

而我们常说的跨域是狭义的,是由浏览器同源策略引起的一类请求场景.

The same-origin policy is a critical security mechanism that restricts how a document or script loaded from one origin can interact with a resource from another origin. It helps isolate potentially malicious documents, reducing possible attack vectors.

来自 MDN

如果两个域名的协议,域名,端口都相同,那我们就说这两个域名是同源的.

2. 同源策略限制些什么?

  1. 不能向工作在不同源的服务请求数据,即不能发送 Ajax 请求;
  2. 无法获取不同源的 document / cookies 等 BOM 和 DOM,可以说任何有关另一个源的信息都无法得到.

3. 为什么会有同源策略

3.1 为什么要限制不同源发送请求

假设两个页面,a 页面和 b 页面.如果没有任何限制,b 页面可以向 a 页面请求任何信息,那如果 a 页面是个
银行之类的页面,那就可以进行转账之类的请求.
那既然如此,为什么不限制写,只限制读?
因为如果连请求都发送不出去,那就不能做跨域资源共享了.

3.2 为什么限制跨域的 DOM 读取?

如果不加以限制,很容易通过 iframe 伪装其网站.进而可以获取用户的登录信息等.

4. 跨域的解决方式

4.1 CORS

服务器设置:

ACCESS-CONTROL-ALLOW-ORIGIN: *

只要浏览器检测到响应头带上了 CORS,并且允许的源包括了本网站,那么就不会拦截请求响应。

CORS 分为"简单请求"以及"预检请求":

  1. 简单请求
    使用下列方法之一:

    • GET
    • POST
    • HEAD

    以及满足 Fetch 规范定义了对 CORS 安全的首部字段集合,不得人为设置该集合之外的其他首部字段。
    而且 Content-Type 的值仅为下列三者之一:

    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded
  2. 预检请求
    与上述简单请求不一样."需预检的请求"要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,
    以获知服务器是否允许该实际请求。"预检请求"的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。
    当满足以下任一条件时,即应首先发送预检请求:

    • 非简单请求的方法
    • 人为设置了对 CORS 安全的首部字段集合之外的其他首部字段。
    • 非简单请求的 Content-Type
    • 请求中的XMLHttpRequestUpload 对象注册了任意多个事件监听器。
    • 请求中使用了ReadableStream对象。

另外,还有附带身份验证的请求,也就是携带 cookies.
这个需要前端在请求实例中设置:

// 将 XMLHttpRequest 的 withCredentials 标志设置为 true
const xml = new XMLHttpRequest();
// ...
xml.withCredentials = true;

这时,后端需要作出相应的设置.

来自MDN

4.2 JSONP

JSONP 能够跨域的原理就是:动态创建 script 标签,利用 script 标签的 src 请求没有跨域的限制.

代码示例
function updateList (data) {
    console.log(data);
}
let tag = document.createElement("script")
tag.src = "http://otherdomain.com/request?callback=updateList";
document.head.appendChild(tag);

代码定义一个全局函数,然后把这个函数名添加到 script 标签中 src 属性的参数 callback 中,
script 的 src 就是需要跨域的请求.服务端收到请求之后,将数据放入 callback 属性的属性值中:
updateList("somedata"),然后返回给客户端:

// script 响应返回的js内容为
updateList([{
    name: 'hello'
}]);

也就是客户端执行 传递的方法 updateList ,函数的参数即是本次跨域请求返回的数据.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值