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

什么是跨域

在前端开发中,我们经常会遇到 跨域 问题,那么,什么是 跨域 呢?用大白话来讲,跨域 就是我们访问了别人的资源。比如说我们通过 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.代理

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

基本过程

相关推荐
muddjsv1 小时前
前端性能优化实战:从加载到渲染的全面提速指南
前端·性能优化
deli0070072 小时前
JSON 树形查看器:粘贴即解析,折叠展开一目了然
前端·数据库·json·ai编程
guanguan0_02 小时前
PageProxy:页面维度接口地图 + 一键场景切换
前端·ai编程·请求代理·proxy工具
liangshanbo12152 小时前
虚拟列表深度面试题整理
java·开发语言·前端
IT_陈寒3 小时前
Redis内存警告竟是因为这个不起眼的配置项
前端·人工智能·后端
lilian2333 小时前
Harmony os 技术实战|拼豆制图43:压缩字符矩阵上线前如何拦住错位图纸
开发语言·前端·华为·矩阵·harmonyos
kyriewen3 小时前
我踩了3次同一个坑才明白:JavaScript里比0.1+0.2更隐蔽的5个数字陷阱
前端·javascript·面试
徐小夕3 小时前
表格、文档、甘特、大屏、表单一站打通:pxcharts超级表格4.0正式上线!
前端·算法·github
用户594404103564 小时前
Vue3 + TypeScript + Leaflet.js 实战:构建企业级地理信息应用
前端
kyson_4 小时前
一次搭好 ESLint + Prettier + Husky + lint-staged 前端代码工作流
前端