彻底搞懂前端跨域解决方案

news2024/9/24 7:21:29

 

目录

1浏览器的同源策略

1.1同源策略概述

1.2什么是源(origin)?

2跨域会受到哪些限制

2.1限制DOM访问

2.2限制Cookie访问

2.3限制Ajax获取数据

3几个注意点 

4CORS 解决 Ajax 跨域问题

4.1CORS 概述

4.2CORS 解决简单请求跨域

4.3简单请求与复杂请求

4.4CORS 解决复杂请求跨域

4.5借助 cors 库快速完成配置

5JSONP 解决跨域问题

6配置代理解决跨域

6.1自己配置代理服务器

6.2使用 Nginx 搭建代理服务器

6.3借助脚手架搭建服务器 


代码地址 git clone https://gitee.com/childe-jia/cross-domain-test.git

1浏览器的同源策略

1.1同源策略概述


同源策略是浏览器为确保资源安全,而遵循的一种策略,该策略对访问资源进行了一些限制。
W3C 上对同源策略的说明:Same origin policy。

1.2什么是源(origin)?


1源的组成部分

image.png


2下面表格中,只有最后一行的两个源是同源。

源 1

源 2

是否同源

http://www.xyz.com/home

https://www.xyz.com/home

⛔非同源️

http://www.xyz.com/home

http://mail.xyz.com/home

⛔非同源

http://www.xyz.com:8080/home

http://www.xyz.com:8090/home

⛔非同源

http://www.xyz.com:8080/home

http://www.xyz.com:8080/search

✅同 源︎

 

3同源请求

image.png


4非同源请求

image.png


5总结:『所处源』与『目标源』不一致,就是『非同源』,又称『异源』或『跨域』

2跨域会受到哪些限制


例如有两个源:『源A』和『源B』,它们是『非同源』的,那么浏览器会有如下限制:

2.1限制DOM访问

『源A』的脚本不能访问『源B』的 DOM。

<!-- <iframe id="framePage" src="./demo.html"></iframe> -->
<iframe id="framePage" src="https://www.baidu.com"></iframe>

<script type="text/javascript" >
  function showDOM(){
    const framePage = document.getElementById('framePage')
    console.log(framePage.contentWindow.document) //同源的可以获取,非同源的无法获取
  }
</script>

2.2限制Cookie访问

『源A』不能访问『源B』的 cookie

<iframe id="baidu" src="http://www.baidu.com" width="500" height="300"></iframe>

<script type="text/javascript" >
  // 访问的是当前源的cookie,并不是baidu的cookie
  console.log(document.cookie)
</script>

2.3限制Ajax获取数据

『源A』可以给『源B』发请求,但是无法获取『源B』响应的数据。

const url = 'https://www.toutiao.com/hot-event/hot-board/?origin=toutiao_pc'
let result = await fetch(url)
let data = await result.json();
console.log(data)

 备注:在上述限制中,浏览器对 Ajax 获取数据的限制是影响最大的一个,且实际开发中经常遇到。

3几个注意点 

  • 1跨域限制仅存在浏览器端,服务端不存在跨域限制。
  • 2即使跨域了,Ajax 请求也可以正常发出,但响应数据不会交给开发者。
  • 3<link>、<script>、<img>...... 这些标签发出的请求也可能跨域,只不过浏览器对标签跨域不做严格限制,对开发几乎无影响

image.png

4CORS 解决 Ajax 跨域问题

4.1CORS 概述

CORS 全称:Cross-Origin Resource Sharing(跨域资源共享),是用于控制浏览器校验跨域请求的一套规范,服务器依照 CORS 规范,添加特定响应头来控制浏览器校验,大致规则如下:
●服务器明确表示拒绝跨域请求,或没有表示,则浏览器校验不通过。
●服务器明确表示允许跨域请求,则浏览器校验通过。
备注说明:使用 CORS 解决跨域是最正统的方式,且要求服务器是“自己人”。


4.2CORS 解决简单请求跨域

整体思路:服务器在给出响应时,通过添加Access-Control-Allow-Origin响应头,来明确表达允许某个源发起跨域请求,随后浏览器在校验时,直接通过。

image.png

服务端核心代码(以express框架为例):

// 处理跨域中间件
function corsMiddleWare(req,res,next){
  // 允许 http://127.0.0.1:5500 这个源发起跨域请求
  // res.setHeader('Access-Control-Allow-Origin','http://127.0.0.1:5500')
  
  // 允许所有源发起跨域请求
  res.setHeader('Access-Control-Allow-Origin','*')
  next()
}

// 配置路由并使用中间件
app.get('/',corsMiddleWare,(req,res)=>{
  res.send('hello!')
})

4.3简单请求与复杂请求

CORS 会把请求分为两类,分别是:① 简单请求、② 复杂请求。

简单请求

复杂请求

✅请求方法(method)为:GET、HEAD、POST

1不是简单请求,就是复杂请求。
2复杂请求会自动发送预检请求。

✅请求头字段要符合《CORS 安全规范》
简记:只要不手动修改请求头,一般都能符合该规范。

✅请求头的Content-Type的值只能是以下三种:
●text/plain
●multipart/form-data
●application/x-www-form-urlencoded

关于预检请求:

  • 1发送时机:预检请求在实际跨域请求之前发出,是由浏览器自动发起的。
  • 2主要作用:用于向服务器确认是否允许接下来的跨域请求。
  • 3基本流程:先发起OPTIONS请求,如果通过预检,继续发起实际的跨域请求。
  • 4请求头内容:一个OPTIONS预检请求,通常会包含如下请求头:

请求头

含义

Origin

发起请求的源

Access-Control-Request-Method

实际请求的 HTTP 方法

Access-Control-Request-Headers

实际请求中使用的自定义头(如果有的话)

4.4CORS 解决复杂请求跨域

1第一步:服务器先通过浏览器的预检请求,服务器需要返回如下响应头:

响应头

含义

Access-Control-Allow-Origin

允许的源

Access-Control-Allow-Methods

允许的方法

Access-Control-Allow-Headers

允许的自定义头

Access-Control-Max-Age

预检请求的结果缓存时间(可选)

image.png

2第二步:处理实际的跨域请求(与处理简单请求跨域的方式相同)

image.png

服务端核心代码:

// 处理预检请求
app.options('/students', (req, res) => {
  // 设置允许的跨域请求源
  res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500')
  // 设置允许的请求方法
  res.setHeader('Access-Control-Allow-Methods', 'GET')
  // 设置允许的请求头
  res.setHeader('Access-Control-Allow-Headers', 'school')
  // 设置预检请求的缓存时间(可选)
  res.setHeader('Access-Control-Max-Age', 7200)
  // 发送响应
  res.send()
})

// 处理实际请求
app.get('/students', (req, res) => {
  // 设置允许的跨域请求源
  res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500')
  // 随便设置一个自定义响应头
  res.setHeader('abc',123)
  // 设置允许暴露给客户端的响应头
  res.setHeader('Access-Control-Expose-Headers', 'abc')
  // 打印请求日志
  console.log('有人请求/students了')
  // 发送响应数据
  res.send(students)
})

4.5借助 cors 库快速完成配置

上述的配置中需要自己配置响应头,或者需要自己手动封装中间件,借助cors库,可以更方便完成配置

●安装cors

npm i cors

●简单配置cors

app.use(cors())

●完整配置cors

// cors中间件配置
const corsOptions = {
  origin: 'http://127.0.0.1:5500', // 允许的源
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS'], // 允许的方法
  allowedHeaders: ['school'], // 允许的自定义头
  exposedHeaders: ['abc'], // 要暴露的响应头
  optionsSuccessStatus: 200 // 预检请求成功的状态码
};

app.use(cors(corsOptions)); // 使用cors中间件

默认js是不能访问后端设置的响应头的,需要后端暴露

5JSONP 解决跨域问题

1JSONP 概述: JSONP 是利用了<script>标签可以跨域加载脚本,且不受严格限制的特性,可以说是程序员智慧的结晶,早期一些浏览器不支持 CORS 的时,可以靠 JSONP 解决跨域。


2基本流程:

  • ○第一步:客户端创建一个<script>标签,并将其src属性设置为包含跨域请求的 URL,同时准备一个回调函数,这个回调函数用于处理返回的数据。
  • ○第二步:服务端接收到请求后,将数据封装在回调函数中并返回。
  • ○第三步:客户端的回调函数被调用,数据以参数的形势传入回调函数。

3图示:

image.png

4代码示例:

<button onclick="getTeachers()">获取数据</button>

<script type="text/javascript" >
  function callback(data){
    console.log(data)
  }

  function getTeachers(url){
    // 创建script元素
    const script = document.createElement('script')
    // 指定script的src属性
    script.src= 'http://127.0.0.1:8081/teachers'
    // 将script元素添加到body中触发脚本加载
    document.body.appendChild(script)
    // script标签加载完毕后移除该标签
    script.onload = ()=>{
      script.remove()
    }
  }
</script>

5jQuery 封装的 jsonp

?callback=?' 为固定格式 会自动解析

$.getJSON('http://127.0.0.1:8081/teachers?callback=?',(data)=>{
  console.log(data)
})

6配置代理解决跨域

6.1自己配置代理服务器

服务器之间是没有跨域问题的,要使用express 启动静态资源保证自己的服务器跟页面在同源下

// 启动静态资源 让服务器跟页面同一个源
app.use(express.static("./public"));

借助http-proxy-middleware配置代理

const { createProxyMiddleware } = require('http-proxy-middleware');

app.use('/api',createProxyMiddleware({
  target:'https://www.toutiao.com',
  changeOrigin:true,
  pathRewrite:{
    '^/api':''
  }

 

优点:

  • 功能丰富:http-proxy-middleware提供了丰富的配置选项,可以满足各种代理需求。
  • 可以灵活配置多个代理:可以配置多个代理服务器,分别对应不同的接口路径。
  • 可以拦截请求:可以通过自定义的处理函数对请求进行拦截和修改。

缺点:

  • 配置相对复杂:需要了解http-proxy-middleware库的配置规则和参数。
  • 不适用于生产环境:http-proxy-middleware主要用于开发环境,不适用于生产环境。

使用场景:

  • 适用于使用任何构建工具的前端项目,可以与任何开发服务器配合使用。
  • 适用于需要灵活配置多个代理服务器的场景。
  • 适用于需要对请求进行拦截和修改的场景。

6.2使用 Nginx 搭建代理服务器

整体思路:让nginx充当两个角色,既是 静态内容服务器,又是代理服务器。

修改nginx配置如下,注意nginx的根目录最好不是 C 盘

# 配置nginx根目录
location / {
  root   D:\dist;
  index  index.html index.htm;
}
 
# 配置代理
location /dev/ {
  # 设置代理目标
  proxy_pass http://sph-h5-api.atguigu.cn/;
}

2修改前端项目,让所有请求都转发给 /dev,随后重新打包

const request = axios.create({
  baseURL:'/dev',
  timeout:10000
})

随后直接访问nginx服务器即可,例如 nginx如果运行在8099端口,则访问

http://localhost:8099

随后会遇到刷新404问题,追加nginx配置来解决

 
# 配置nginx根目录
location / {
  root   D:\dist;
  index  index.html index.htm;
  try_files $uri $uri/ /index.html; # 解决刷新404
}
# 配置代理
location /dev/ {
  # 设置代理目标
  proxy_pass http://sph-h5-api.atguigu.cn/;
}

加上这两个“/”就剔除掉了dev

6.3借助脚手架搭建服务器 

1. 使用vue.config.js文件配置代理:

在Vue项目的根目录下创建一个vue.config.js文件,并添加以下代码:

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://api.example.com',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }
}

上述代码中,我们使用devServer配置项来配置代理服务器。其中proxy属性用于配置代理的规则,/api表示需要代理的接口路径。target属性表示代理的目标服务器地址,changeOrigin属性表示是否改变请求的源地址,pathRewrite属性用于重写请求的路径。

优点:

  • 配置简单:使用webpack-dev-server的代理配置,只需要在webpack配置文件中进行简单的配置即可。
  • 功能全面:webpack-dev-server提供了丰富的配置选项,可以满足大部分代理需求。
  • 可以拦截请求:可以通过自定义的处理函数对请求进行拦截和修改。

缺点:

  • 需要重启服务器:配置修改后需要重新启动webpack-dev-server才能生效。
  • 不适用于生产环境:webpack-dev-server主要用于开发环境,不适用于生产环境。

使用场景:

  • 适用于使用webpack构建的前端项目,通过webpack-dev-server来启动开发服务器的场景。
  • 适用于需要简单的代理配置,并且不需要频繁修改代理配置的场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1920943.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

骑士人才系统74cms专业版实现本地VUE打包和在线升级方法以及常见问题

骑士人才系统我就不多说了目前来说我接触的人才系统里面除了phpyun就是骑士人才了&#xff0c;两个历史都很悠久&#xff0c;总起来说功能方面各分伯仲&#xff0c;前几期我作过Phpyun的配置教程这次我们针对骑士人才系统说说怎么使用VUE源码本地一键打包后台和在线升级方式&am…

基于java+springboot+vue实现的新闻稿件管理系统(文末源码+Lw)109

基于SpringBootVue的实现的新闻稿件管理系统&#xff08;源码数据库万字Lun文流程图ER图结构图演示视频软件包&#xff09; 系统功能&#xff1a; 新闻稿件管理系统管理员功能有个人中心&#xff0c;用户管理&#xff0c;记者管理&#xff0c;审批员管理&#xff0c;新闻分类…

GLM-4-9B 支持 Ollama 部署

ollama的安装我们在前面已经介绍了&#xff0c;现在我们看下GLM-4-9B的使用 GLM-4-9B 是智谱 AI 推出的最新一代预训练模型 GLM-4 系列中的开源版本。在语义、数学、推理、代码和知识等多方面的数据集测评中&#xff0c; GLM-4-9B 在各项能力上均表现出卓越的能力。 具体可参见…

品牌电商价格管控的方法与选择

电商平台的蓬勃发展为众多品牌开辟了线上渠道的流通机遇。随着品牌经销渠道的持续拓展&#xff0c;越来越多的品牌不得不应对线上乱价、低价、窜货、假货等一系列渠道问题。那么&#xff0c;如何对电商价格实施有效的管控&#xff1f;品牌是应当自行组建团队专门负责&#xff0…

不同型号的GD32 MCU如何区分?

大家是否碰到过以下应用场景&#xff1a;同一套软件代码希望跑在不同型号的GD32 MCU中&#xff0c;但有些地方需要根据MCU型号进行调整&#xff1f;或者上位机或其他MCU与GD32 MCU通信时需要知道对应的MCU型号是哪个&#xff1f; 此时&#xff0c;我们就需要了解如何获取以及区…

2024【kali渗透测试】到底该如何学?

1、渗透测试是什么&#xff1f; 渗透测试&#xff0c;是为了证明网络防御按照预期计划正常运行而提供的一种机制。渗透测试是通过各种手段对目标进行一次渗透&#xff08;攻击&#xff09;&#xff0c;通过渗透来测试目标的安全防护能力和安全防护意识。打个比方&#xff1a;比…

MongoDB教程(三):mongoDB用户管理

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、MongoD…

15个卫星影像查看网站

我们在《10个卫星影像查看网站》中&#xff0c;为你分享了10个卫星影像查看网站。 现在又为你搜集整理了5个卫星影像查看网站&#xff0c;现在总计有15个网站可以查看在线卫星影像。 如果你需要在水经微图&#xff08;简称“微图”&#xff09;中加载更多的图源&#xff0c;请…

python库(10):SpaCy库实现NLP处理

1 SpaCy简介 自然语言处理&#xff08;NLP&#xff09;是人工智能领域中一个重要的分支。它旨在使计算机能够理解、解释和生成人类语言。Python中的SpaCy库提供了丰富的功能和工具&#xff0c;SpaCy是一个开源的软件库&#xff0c;用于处理和操作自然语言文本&#xff0c;可以…

渗透测试-nmap常用的漏扫命令

nmap常用的漏扫命令 1、扫描单个目标地址&#xff1a; Nmap 192.168.128.30 2、扫描多个目标地&#xff1a; Nmap 192.168.128.130 192.168.128.129 3、扫描一个范围内的目标地址&#xff1a; Nmap 192.168.128.129-130 4、扫描目标地址所在的某个网段 Nmap 192.168.12…

2024年高职大数据实验室建设及大数据实训平台整体解决方案

随着大数据技术的迅猛发展&#xff0c;高职院校的大数据实验室建设与实训平台打造正逐渐成为推动教育现代化的关键环节。为了培养出符合未来社会需求的高素质技术技能型人才&#xff0c;2024年的高职大数据实验室建设方案需从以下几个方面着手&#xff1a; 首先&#xff0c;实…

Docker镜像和容器的管理

1 Docker镜像管理操作 开启镜像加速 根据关键字查询镜像 下载查看镜像 详细镜像信息 查看latest版本 上传镜像到阿里云仓库 2 Docker容器操作 关于容器根据第一个pid进程是否能正常在前台运行

硬件开发笔记(二十五):AD21导入电解电容原理图库、封装库和3D模型

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/140344547 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

Math/System/Runtime/Object

1、Math &#xff08;1&#xff09;常用方法 类型方法名说明public static intabs (int a)返回整数的绝对值public static doublepow (double a,double b)计算a的b次幂的值public static int max (int a,int b) 获取两个int值中的较大值public static intmin (int a,int…

【吊打面试官系列-ZooKeeper面试题】简述 Zookeeper 文件系统?

大家好&#xff0c;我是锋哥。今天分享关于 【简述 Zookeeper 文件系统?】面试题&#xff0c;希望对大家有帮助&#xff1b; 简述 Zookeeper 文件系统? Zookeeper 提供一个多层级的节点命名空间&#xff08;节点称为 znode&#xff09;。与文件系统不同的是&#xff0c;这些节…

“南征北战”| 卓翼飞思技术领航,助力人工智能大赛上海赛区选拔赛圆满落幕

卓翼飞思继6月支持辽宁赛区选拔赛圆满收官后&#xff0c;近日再次技术助力&#xff0c;为上海赛区的比赛画上圆满句号。值得一提的是&#xff0c;在此次比赛中来自上海工程技术大学、同济大学、上海商学院、上海农林职业技术学院&#xff0c;使用卓翼飞思设备的5支参赛队伍&…

【Java EE】统一功能返回

一、拦截器 1.1 拦截器的作用 在对于数据库进行增删查改的时候&#xff0c;如果当前页面不检查用户是否登录&#xff0c;然后就能操作成功是不合理的&#xff0c;解决方法有两个&#xff1a; 对于已经写好的每个接口都加上一个判断&#xff0c;从Session中获取用户信息&…

嵌入式开发过程中,常见报错以及解决方法

编写不易&#xff0c;仅供学习&#xff0c;参考谢谢&#xff0c;还望理解。 #常见报错 文件最后一行没有新行 翻译&#xff1a;文件的最后一行结束时没有新行 解决方法&#xff1a;定位到&#xff0c;提示报错的 .h 文件 报错行 &#xff0c;加上一个新行 函数定义时与官方提…

体育资讯小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;球员管理&#xff0c;教练管理&#xff0c;赛事日程管理&#xff0c;赛事类型管理&#xff0c;联赛积分榜管理 开发系统&#xff1a;Windows 架构模式&#xff1a;SSM JDK版本&a…