浅析跨域原理及常用的跨域解决方案

什么是跨域

在前端开发中,我们经常会遇到 跨域 问题,那么,什么是 跨域 呢?用大白话来讲,跨域 就是我们访问了别人的资源。比如说我们通过 img link script 或者 接口请求 等方式来访问别人的资源,都是属于 跨域

当碰见 跨域 时,浏览器会有固定格式的报错信息,如下

Access to XMLHttpRequest at 'xxx' from origin 'yyy' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

我们会发现,通过 img linl script 标签来请求别的资源时,好像都没有相关的 跨域 报错信息(有些资源会做跨域拦截,禁止访问),那是因为浏览器对这些由 标签元素 跨域请求限制不大,基本都是直接放行的。

那么,为啥会有 跨域 问题呢,以及是如何产生的呢?

产生跨域的原因

产生跨域的原因主要是来在 浏览器的同源策略, 此处有两个重点 浏览器同源

跨域 发生的位置是在 浏览器,而非 服务器。不同服务器之间请求资源是不存在跨域问题的。

浏览器为了保护用户的安全,使用 同源策略 阻止一些资源的解析和执行。

同源策略是一个重要的安全策略,它用于限制一个源的文档或者它加载的脚本如何能与另一个源的资源进行交互。

它能帮助阻隔恶意文档,减少可能被攻击的媒介。例如,它可以防止互联网上的恶意网站在浏览器中运行 JS 脚本,从第三方网络邮件服务(用户已登录)或公司内网(因没有公共 IP 地址而受到保护,不会被攻击者直接访问)读取数据,并将这些数据转发给攻击者。

什么是同源策略

我们先来看下一个域名的组成吧

同源指的是: 协议 域名 端口号 必须一致

源1 源2 是否同源
a.com:80/b a.com:80/b 否 【协议不同】
a.com:80/b c.com:80/b 否 【域名不同】
a.com:80/b a.com:81/b 否 【端口不同】
a.com:80/b a.com:80/b/c

需要注意的一点,发生 跨域 时,浏览器会发起具体的请求,只是会对 跨域 请求进行报错提示,我们一起来看下具体的请求过程吧,如下图

跨域解决方案

1.CORS

CORS是 Cross Origin Resource Sharing 的缩写,翻译过来是 跨来源资源共享

CORS式一套机制,用于浏览器校验跨域请求。它的基本原理是:

只要服务器明确表示允许,则校验通过,服务器明确拒绝或没有表示,则校验不通过

这个也就决定了跨域目标服务器必须是自己的服务器

浏览器将CORS请求分为 简单请求预检请求(也叫非简单请求)

简单请求

简单请求 需要满足以下两个条件

  1. 请求方法为: HEAD GET POST
  2. HTTP的头信息不超出以下字段
  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-type: 只限于三个值: text/plain multipart/form-data application/x-www-form-urlencoded

请求过程

预检请求

不满足 简单请求 的都会转为 预检请求

请求过程

2.JSONP

JSONP是 JSON with Padding 的缩写

JSONP 是利用浏览器对标签的请求跨域限制较小的原理,实现的跨域

基本过程

jsonp整体工作流程(把jsonp封装到按钮点击事件里面)

  1. 浏览器: 声明函数接收服务器响应数据
  2. 浏览器: 点击按钮给页面添加script,添加额外参数callback=函数名
  3. 服务器 : 响应函数调用js代码 res.send('函数名(响应数据)')
  4. 浏览器: script标签会执行服务器响应的js
javascript 复制代码
// 前端

function CallBack(res) {
  console.log(res)
}

function JSONP_QUERY(url) {
  const script = document.createElement("script");
  script.src = url;
  script.onload = function() {
    script.remove()
  }
  document.body.appentChild(script);
}

document.querySelector("button").onclick = function() {
  JSONP_QUERY("http://www.abc.com?callback=CallBack");
}


// 后端
app.get("/abc", (req, res) => {
  const callback = req.query.callback;
  res.send(`${callback}(${data})`)
})

3.代理

以上两个方案,有个致命的缺点,就是服务器必须是自己的,所有跨域的的接口请求必须自己来处理,除非让别人服务器去兼容跨域处理,显然是不可行的,碰到这种情况,那我们就需要通过代理服务器来处理,它的基本原理就是利用服务器之间的请求是不在跨域,允许直接请求。

基本过程

相关推荐
caperxi几秒前
前端开发中的防抖与节流
前端·javascript·html
霸气小男几秒前
react + antDesign封装图片预览组件(支持多张图片)
前端·react.js
susu10830189111 分钟前
前端css样式覆盖
前端·css
学习路上的小刘3 分钟前
vue h5 蓝牙连接 webBluetooth API
前端·javascript·vue.js
&白帝&3 分钟前
vue3常用的组件间通信
前端·javascript·vue.js
小白小白从不日白14 分钟前
react 组件通讯
前端·react.js
罗_三金24 分钟前
前端框架对比和选择?
javascript·前端框架·vue·react·angular
Redstone Monstrosity31 分钟前
字节二面
前端·面试
东方翱翔38 分钟前
CSS的三种基本选择器
前端·css
Fan_web1 小时前
JavaScript高级——闭包应用-自定义js模块
开发语言·前端·javascript·css·html