跨域相关的一些问题 ✅

ops/2024/11/27 12:11:30/

当网页从一个源(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/ops/137079.html

相关文章

Stable Diffusion中的自注意力替换技术与Diffusers实现

Stable Diffusion中的自注意力替换技术与Diffusers实现 文章目录 Stable Diffusion中的自注意力替换技术与Diffusers实现摘要Abstract一、机器学习部分1. 注意力计算2. SD中的自注意力替换3. 自注意力替换的应用4. 在 Diffusers 里实现自注意力替换4.1 AttentionProcessor4.2 实…

Git 提交的相对引用

Git 提交的相对引用 在 Git 中&#xff0c;使用 ~ 和 ^ 符号可以帮助你更灵活地引用提交历史中的特定提交。以下是这些符号的具体用法和示例&#xff1a; 1. ~&#xff08;波浪号&#xff09; ~ 符号用于指向上一个或多个父提交。它总是沿着第一个父提交的链向上追溯。 HEA…

react实现模拟chatGPT问答页

目录 需求前端方法用原始的方案用SSE实现方案GET请求POST请求 需求 需要使用react实现模拟chatGPT的页面&#xff0c;后端接口使用流式传输 stream: true&#xff0c;并且用 POST 方法进行传参 前端方法 用原始的方案 大概思路&#xff1a;使用 fetch 接受数据&#xff0c;…

Http 请求协议

HTTP的请求协议 请求数据格式&#xff1a; 请求行 请求数据的第一行&#xff0c;包含请求方式、资源路径、协议及版本。 请求头 从请求数据的第二行&#xff0c;以key: value的格式 常见的请求头 Host&#xff1a;请求的主机名&#xff0c;如&#xff1a;localhost:8080&#x…

Qt界面篇:QMessageBox高级用法

1、演示效果 2、用法注意 2.1 设置图标 用于显示实际图标的pixmap取决于当前的GUI样式。也可以通过设置icon pixmap属性为图标设置自定义pixmap。 QMessageBox::Icon icon(

常见线程安全问题之复合操作

创作内容丰富的干货文章很费心力&#xff0c;感谢点过此文章的读者&#xff0c;点一个关注鼓励一下作者&#xff0c;激励他分享更多的精彩好文&#xff0c;谢谢大家&#xff01; 复合操作的问题本质上和 TOCTOU 是一样的&#xff0c;如果有多个操作&#xff08;如同一变量的读写…

解决 java -jar 报错:xxx.jar 中没有主清单属性

问题复现 在使用 java -jar xxx.jar 命令运行 Java 应用程序时&#xff0c;遇到了以下错误&#xff1a; xxx.jar 中没有主清单属性这个错误表示 JAR 文件缺少必要的启动信息&#xff0c;Java 虚拟机无法找到应用程序的入口点。本文将介绍该错误的原因以及如何通过修改 pom.xm…

工作坊报名|使用 TEN 与 Azure,探索你的多模态交互新场景

GPT-4o Realtime API 发布&#xff0c;语音 AI 技术正在进入一场新的爆发。语音AI技术的实时语音和视觉互动能力将为我们带来更多全新创意和应用场景。 实时音频交互&#xff1a; 允许应用程序实时接收并响应语音和文本输入。自然语音生成&#xff1a; 减少 AI 技术生成的语音…