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

什么是跨域

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

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

基本过程

相关推荐
MickeyCV37 分钟前
Nginx学习笔记:常用命令&端口占用报错解决&Nginx核心配置文件解读
前端·nginx
祈澈菇凉1 小时前
webpack和grunt以及gulp有什么不同?
前端·webpack·gulp
十步杀一人_千里不留行1 小时前
React Native 下拉选择组件首次点击失效问题的深入分析与解决
javascript·react native·react.js
zy0101011 小时前
HTML列表,表格和表单
前端·html
初辰ge1 小时前
【p-camera-h5】 一款开箱即用的H5相机插件,支持拍照、录像、动态水印与样式高度定制化。
前端·相机
HugeYLH1 小时前
解决npm问题:错误的代理设置
前端·npm·node.js
三天不学习2 小时前
Redis面试宝典【刷题系列】
数据库·redis·面试
六个点2 小时前
DNS与获取页面白屏时间
前端·面试·dns
道不尽世间的沧桑2 小时前
第9篇:插槽(Slots)的使用
前端·javascript·vue.js
bin91532 小时前
DeepSeek 助力 Vue 开发:打造丝滑的滑块(Slider)
前端·javascript·vue.js·前端框架·ecmascript·deepseek