跨域相关的一些问题 ✅

news/2024/11/26 19:17:39/

当网页从一个源(https://baidu.com)请求另一个源(如 https://taobao/api)的资源时,就发生了跨域。由于安全原因(防止恶意网站通过脚本访问用户在其他网站上的数据),浏览器对跨域请求设置了限制,这样的机制称为同源策略。

浏览器特有的现象

应该说,跨域不是浏览器特有的现象,跨域几乎在所有客户端都存在,但是同源策略是浏览器特有的。当你在浏览器中执行 AJAX 请求,浏览器首先会检查此请求的源是否合法(即与当前页面的源是否相同)。如果请求是跨域的,浏览器会立即阻止该请求发送(后端会连请求都收不到)。

但是微信小程序,桌面应用和APP等客户端应用是不会受到同源策略的直接限制的,因为他们运行的客户端环境并不是浏览器,但是他们需要遵守的是所处的运行环境的其他规范。比如微信小程序上线后能请求的API必须用的是https协议,而且能请求哪些域名下的API必须在后台自己的小程序管理下面进行登记 (没记错的话,上一次开发小程序至今已有一坤年) ,开发环境下倒是无所谓。

假设我在浏览器端和在微信小程序端同时发送一个请求给后端,那后端收到的请求头分别长什么样子?以下只对比一些关键字段:

1️⃣ 浏览器

  • User-Agent:用来标识当前浏览器类型和版本,例如:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36
  • Referer:重头戏,指示请求来源的 URL,在JavaScript里面对这个字段能进行的修改极端有限,甚至可以说没有,Referer 的值是由浏览器自动设置的。
  • Accept:表示浏览器可以处理的内容类型
  • Cookie:如果有的话

2️⃣ 微信小程序

  • User-Agent:微信小程序的请求头中的 User-Agent 会有不同的格式,通常包含 “MicroMessenger” 字样,例如:Mozilla/5.0 (Linux; Android 10; SM-G9500 Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/12.0 WeChat/8.0.0.1 MiniProgramPlatform/1.0.0.0
  • Referer:微信小程序可以设置特定的 Referer,但也不是在开发过程中能够通过JavaScript来控制的,在使用wx.request的时候Referer由小程序框架自动填充,通常会被设置为小程序的合法请求域名,即你在小程序后台配置的接口域名
  • Accept:通常为*/*
  • Cookie:如果有的话

处理跨域问题(浏览器端)

CORS

首先得知道,CORS并没有直接作用于客户端,CORS配置是服务端的响应头配置,比较关键的字段是以下两个:

const responseHeaders = {"Access-Control-Allow-Origin": "*" // 允许跨域请求的域名"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS" // 允许跨域请求的方法
}

它规定了哪些方法,来自哪些域名的请求可以成功调用服务端的接口,这保护的是服务端的安全性。当浏览器发送跨域请求时,服务器通过 CORS 响应头(如 Access-Control-Allow-Origin)来告诉浏览器是否允许该请求,具体来说,服务器在返回的 HTTP 响应中添加 CORS 相关的头部信息,允许特定的源进行访问

到目前为止,CORS的作用还是停留在对服务器的保护上,但是却抛出了一个问题💡:如果我的请求被浏览器的同源策略所拦截,我压根发不出去,更不可能知道响应头的Access-Control-Allow-Origin到底是什么,那我的AJAX岂不一辈子都发不出去?

所以OPTIONS,预检请求登场。OPTIONS 请求是一种 HTTP 请求方法,用于查询服务器支持的 HTTP 方法及其他选项,而不是直接请求特定资源。根据 CORS 规范,预检请求通常在以下情况下发送:
1️⃣ 请求方法为 PUT、DELETE、PATCH、OPTIONS,或其他非 GET 和 POST 的方法
2️⃣ 如果 Content-Type 头为除 application/x-www-form-urlencodedmultipart/form-datatext/plain 以外的任何值(例如 application/json)
3️⃣ 当请求中包含自定义头部(例如 X-Requested-With)
如果OPTIONS询问目标服务器后发现自己的接下来要发送的请求能够符合服务器那边的CORS配置,那同源策略就会放行,AJAX就能发到后端。

顺便提一嘴,开发微信小程序有时候也得后端配合设置CORS,说不定你的referer一开始没在人家的白名单里呢。

JSONP

JSONP算一种投机取巧的方法,在如果服务器是团队内部的,那还是用CORS。 JSON是不受同源策略限制的,但是这种方法只能支持GET请求而且相对不安全。 至今不知道不安全在哪,被攻击到的我觉得是服务端而不是客户端。

给一个demo,后端用了Egg:

// router.js
module.exports = (app) => {const { router, controller } = app;// JSONP 数据接口router.get('/api/data', controller.home.getData); 
};// home.js
const Controller = require('egg').Controller;
class HomeController extends Controller {async getData() {const { ctx } = this;// 获取回调函数名(来自query传参数)const callback = ctx.query.callback; // 要返回的数据const data = { message: 'Hello from Egg.js!' }; // 检查是否提供了callback参数if (callback) {ctx.body = `${callback}(${JSON.stringify(data)})`; // 返回 JSONP 响应} else {ctx.body = { error: 'No callback provided' }; // 返回错误}}
}
module.exports = HomeController;

前端

<script>function handleResponse(data) {// 处理返回的 JSONP 数据console.log(data);document.getElementById("result").innerText = data.message;}function fetchData() {const script = document.createElement("script");script.src = "http://localhost:7001/api/data?callback=handleResponse"; // 注意 CORS 端口应与后端一致document.body.appendChild(script); // 动态插入 script 标签进行 JSONP 请求}
</script>

但是这种script标签的用法和开发中用的比较多的用script来下载其他库不是一回事。
使用 script 标签发起 JSONP 请求的目的是从不同源(跨域)获取数据。服务端会以一个可调用的 JavaScript 函数的形式返回数据,以便前端能够在加载该脚本后执行回调函数来处理数据。
而用它来加载库是为了引入第三方 JavaScript 代码,以便在你的网页中使用这些库提供的功能。加载后的库通常会直接在全局范围内注册变量。


Proxy

在同源服务器上设置代理,通过中间的服务器转发请求,浏览器请求的是同源服务器,从而绕过同源策略。比较常用的是Nginx的反向代理功能,开发中Webpack和Vite都提供了开启内置的反向代理服务器的功能。
既然要浏览器请求的是同源服务器,那axios里面的url就不能是真正的API URL,而应该是前端应用的生产环境URL,然后在Nginx内做了一次转发,把请求转发到后端服务器去。这种代理和典型的反向代理。

提一嘴正向代理和方向代理。
反向代理是指客户端通过代理服务器发起请求。1️⃣ 客户端只把请求发到代理服务器 2️⃣ 代理服务器接收请求,并根据负载均衡策略或配置将请求转发给一个或多个后端服务器 3️⃣ 后端服务器处理请求后,将响应返回给反向代理服务器 4️⃣ 反向代理服务器再将响应转发回客户端。
如果说反向代理是作用于服务端,那正向代理就是作用于客户端,通常是为了匿名、绕过限制、内容过滤等,比如翻墙用的就是正向代理。了解实在有限,以后再研究研究


iframe标签

可以用iframe实现跨域请求,但是我没用过,甚至连这个标签我都用的很少。

先创建一个主页面,其中嵌入了另一个跨域的页面:

<script>function sendMessage() {const iframe = document.getElementById('myIframe');// 发送消息给 iframeiframe.contentWindow.postMessage('Hello from the main page!', '*');}window.addEventListener('message', (event) => {// 监听来自 iframe 的消息console.log('Received from iframe:', event.data);document.getElementById('result').innerText = event.data;});
</script>
<body><h1>主页面</h1><button onclick="sendMessage()">发送消息到iframe</button><div id="result"></div><iframe id="myIframe" src="https://example.com" width="600" height="400"></iframe>
</body>

再创建一个跨域页面iframe.html,必须支持接收消息和发送响应:

<script>window.addEventListener('message', (event) => {// 监听主页面发送的消息console.log('Received from main page:', event.data);const result = fetch(..........)// 发送响应回主页面event.source.postMessage('Hello from the iframe!', result);});
</script>

运行方法:

  1. 将主页面的 index.html 文件放在一个能够访问的 Web 服务器上。
  2. 将跨域页面的 iframe.html 放在另一个可以访问的地址上(务必符合跨源域)。
  3. 在主页面上,通过点击按钮“发送消息到 iframe”,会发送一个消息给嵌入的 iframe。
  4. iframe 页面接收到消息后,会回复一个消息,主页面也会接收到这个回复。

http://www.ppmy.cn/news/1550122.html

相关文章

《基于FPGA的便携式PWM方波信号发生器》论文分析(三)——数码管稳定显示与系统调试

一、论文概述 基于FPGA的便携式PWM方波信号发生器是一篇由任青颖、庹忠曜、黄洵桢、李智禺和张贤宇 等人发表的一篇期刊论文。该论文主要研究了一种新型的信号发生器&#xff0c;旨在解决传统PWM信号发生器在移动设备信号调控中存在的精准度低和便携性差的问题 。其基于现场可编…

三种蓝牙架构实现方案

一、蓝牙架构方案 1、hostcontroller双芯片标准架构 手机里面包含很多SoC或者模块&#xff0c;每颗SoC或者模块都有自己独有的功能&#xff0c;比如手机应用跑在AP芯片上&#xff0c;显示屏&#xff0c;3G/4G通信&#xff0c;WiFi/蓝牙等都有自己专门的SoC或者模块&#xff0…

(功能测试)第五章 APP项目测试

熟悉APP项目 模型介绍 更新速度取决于开发模型 上面所说的京东&#xff0c;就是做一次发布一次&#xff0c;传统行业用的是瀑布模型&#xff0c;互联网行业用的是敏捷模型&#xff0c; 瀑布模型就像是瀑布一般&#xff0c;从上到下&#xff0c;上一个环节没有完成下一个环节是没…

牛客周赛69第一题:JAVA

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 小歪有两个整数 a 和 b &#xff0c;他想找到这样一个整数 c &#xff0c;使得这三个整数在经过排序后能成为一个等差数列。 输入描述: 在一行上输入两个整数 a,b(1≦a,b≦106)a,b\left(1 \l…

【失败经验】将算法模型封装为安卓应用

背景&#xff1a;不懂安卓开发&#xff0c;希望能使用大模型编码完成安卓应用生成&#xff0c;调用算法模型进行预测。 模型准备&#xff1a; pip方案安装pcnn&#xff1b; 然后需要将pytorch训练完成的算法模型保存为torchscript模型&#xff0c;然后使用pcnn转换为ncnn的模…

DICOM图像深入解析:为何部分DR/CR图像默认显示为反色?

概述 在数字医学影像处理中,CR(Computed Radiography,计算机放射摄影)和DR(Digital Radiography,数字放射摄影)技术广泛应用于医疗影像获取与分析。然而,临床实践中常常遇到这样一个问题:部分CR/DR图像在默认打开时呈现为反色(即负片效果),需手动反色后才能正常阅片…

【C语言】传值调用与传址调用:深度解析与实现

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 &#x1f4af;前言&#x1f4af;什么是传值调用和传址调用&#xff1f;1. 传值调用&#xff08;Call by Value&#xff09;2. 传址调用&#xff08;Call by Reference&#xff09; &#x1f4af;传值调…

故障排除-------K8s挂载集群外NFS异常

故障排除-------K8s挂载集群外NFS异常 1. 故障现象2. 原因梳理2.1 排查思路2.2 确认yaml内容2.3 创建k8s内的nfs测试2.3.1 创建nfs和svc2.3.2 测试创建pvc2.3.3 测试结果 2.4 NFS服务端故障排除2.4.1 网络阻断排除2.4.2 排除服务状态问题2.4.3 排查NFS权限问题 3. 故障排除 1. …