跨域的多种方案详解
浏览器的同源策略是为了保护用户的安全,限制了跨域请求。同源策略要求请求的域名、协议和端口必须完全一致,只要有一个不同就会被认为是跨域请求。
本文列举了一些处理跨域请求的解决方案:
- JSONP
- CORS跨域资源共享
- http proxy
- nginx反向代理
- webSocket 协议跨域
- postMessage
- document.domain + iframe
- window.name + iframe
- location.hash + iframe
1. JSONP
先说缺点,JSONP只能处理get请求。
script、iframe、img、link 等src属性,不存在跨域请求的限制。利用这个特性可以实现跨域请求

首先在服务器端用node+express模拟一个接口
let express = require("express");
let app = express();app.listen(8001, (_) => {console.log("服务器已启动!");
});app.get("/list", (req, res) => {// let { callback = Function.prototype } = req.query;let callback = req.query.callback;let data = {code: 200,messsage: "程序猿小野",};res.send(`${callback}(${JSON.stringify(data)})`);
});
1)使用jquery的ajax实现(axios的jsonp方法也可以)
$.ajax({url: "http://127.0.0.1:8001/list",method: "get",dataType: "jsonp", // => 执行的JSONP的请求,不加这一行会报跨域错误,has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.success: (res) => {console.log(res);},
});
web本地启动的服务器地址是:http://127.0.0.1:5501,服务器的地址是:http://127.0.0.1:8001/
不加dataType:"jsonp"时会报下面的跨域错误

2)利用 script标签的src属性
function handleResponse(data) {console.log("接收到的数据:", data);
}let scriptEle = document.createElement("script");
scriptEle.src = `http://127.0.0.1:8001/list?callback=handleResponse`;
document.head.appendChild(scriptEle);
成功接收到数据:

2. CORS跨域资源共享(必须掌握)
<script>axios.get("http://127.0.0.1:8001/list").then((res) => {console.log(res.data);}).catch((err) => {console.error(err);});
</script>

let express = require("express");
let app = express();app.listen(8001, (_) => {console.log("服务器已启动!");
});app.use((req, res, next) => {res.header("Access-Control-Allow-Origin", "http://127.0.0.1:5501");
// res.header("Access-Control-Allow-Origin", "*");
// res.header("Access-Control-Allow-Credentials", "true"); // 后端允许发送Cookienext();
});app.get("/list", (req, res) => {let data = {code: 200,messsage: "程序猿小野",};res.send(`${JSON.stringify(data)}`);
});

3. http proxy (必须掌握)
这种情况是目前开发时,前端调试接口解决跨域问题,最常见的处理方法。一般通过webpack webpack-dev-server实现。用vue-cli创建的项目可以在vue.config.js中配置。
index.js
import axios from "axios";// axios.get("http://127.0.0.1:8001/user/list").then((res) => {
axios.get("/user/list").then((res) => {console.log(res);
});
没有配置proxy代理时,请求报错:

vue.config.js配置示例:
devServer: {open: true,port: 10003,headers: {"Access-Control-Allow-Origin": "*",},proxy: {"/": {target: "http://127.0.0.1:8001/",secure: false,changeOrigin: true,},},},
webpack.config.js 配置示例:
let path = require("path");
let HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {mode: "production",entry: "./src/index.js",output: {filename: "bundle.min.js",path: path.resolve(__dirname, "build")},devServer: {port: 3000,progress: true,contentBase: "./build",proxy: {"/": {target: "http://127.0.0.1:8001",changeOrigin: true},},},plugins: [new HtmlWebpackPlugin({template: "./src/index.html",filename: "index.html",})],
};
配置后请求成功:

4. nginx反向代理(必须掌握)
nginx 相关的内容比较多,有时间可以另开一个帖子去说。这里举一个我在实际开发过程中遇到的场景。我们的页面调其他前端模块的服务跨域了,在开发中没有,为什么上线后会出现呢。主要是因为开发时前端的服务都在同一个服务器上,不会产生跨域情况。上线部署在不同的服务器,这时候就出现了如下错误:

修改ngnix的相关配置,实际ip地址和对应的服务名已处理。修改后跨域问题解决:
upstream testxxx {server 127.0.0.1:3000 weight=1;server 127.0.0.2:4000 weight=1;
}location /fuwuming{proxy_set_header Host $host:$server_port;proxy_set_header X-Real-IP $remote_addr;proxy_set_header REMOTE-HOST $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass http://testxxx/fuwuming;
}
查看结果:

5. webSocket 协议跨域(必须掌握)
WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。
原生WebSocket API使用起来不太方便,下面案例借助了socket.io.js的库,,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
前端代码:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><div>user input:<input type="text" /><button id="button">发送</button></div><script src="./socket.io-4.7.2.js"></script><script>var socket = io("http://127.0.0.1:3000");// 与服务器连接成功socket.on("connect", () => {console.log("socket链接成功!" + socket.id);});// 接收服务器发送的消息socket.on("sendToClient", (message) => {console.log(message);});let sendToServerFunc = function () {let inputVal = document.getElementsByTagName("input")[0].value;// 向服务器发送消息socket.emit("sendToServer", {message: `我是客户端: ${inputVal}`,});};document.getElementsByTagName("input")[0].onblur = sendToServerFunc;document.getElementById("button").onclick = sendToServerFunc;</script></body>
</html>
node服务器代码:
// 导入express模块
const express = require('express')
// 引入http创建服务器实例的方法
const {createServer} = require('http')
const {Server} = require('socket.io')
// 创建express的服务器实例
const app = express()
// 创建http服务器实例
const httpServer = createServer(app)
// 创建socket.io的实例
const io = new Server(httpServer,{// 处理cors,解决跨域问题cors:{// origin: "http://127.0.0.1:5500",//需要跨域资源共享的地址origin: "http://127.0.0.1:5501",//需要跨域资源共享的地址allowedHeaders: ["my-custom-header"],credentials: true}
})
// 监听客户端连接,回调函数会传递本次连接的socket
io.on('connection',(socket) => {console.log(socket.id)// 监听到客户端发送的消息socket.on('sendToServer',(message) => {console.log(message)// 向客户端发送消息socket.emit('sendToClient',{message:'你好我是服务端,让我们来聊天呀'})})
} )// 调用listen方法,指定端口号并启动web服务器
httpServer.listen(3000,() =>{console.log('server is running at http://127.0.0.1:3000')
})
效果如下:

6. postMessage
MDN关于postMessage的介绍:

测试案列:
先用node启动两个服务器,不同端口,模拟跨域场景。
node serverA.js node serverB.js
let express = require("express");
let app = express();app.listen(1001, (_) => {console.log("服务器A已启动!");
});app.use(express.static("./"));
let express = require("express");
let app = express();app.listen(1002, (_) => {console.log("服务器B已启动!");
});app.use(express.static("./"));
A.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><h1>A 页面</h1><iframe id="iframe" src="http://127.0.0.1:1002/B.html" frameborder="0" style="display: none;"></iframe><script>iframe.onload = function () {iframe.contentWindow.postMessage('这是A页面传过来的数据AAA', '*');}// 监听B页面传递的消息window.onmessage = function(res){console.log(res);}</script>
</body>
</html>
B.html
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><h1>B 页面</h1><script>// 监听A页面传递的消息window.onmessage = function (res) {console.log(res);res.source.postMessage("这是B页面传过来的数据BBB", res.origin);};</script></body>
</html>
下面几种方案只做了解,实际上几乎用不到。
7. document.domain + iframe (只做了解)
此方案只能实现:同一个主域,不同子域之间的操作
比如:http://www.domain.com/a.html 和 http://child.domain.com/b.html 属于同一个主域
<iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
<script>document.domain = 'domain.com';var user = 'admin';
</script>
<script>document.domain = 'domain.com';// 获取父窗口中变量console.log(window.parent.user);
</script>
8. window.name + iframe(只做了解)
三个页面:A.html地址为:http://127.0.0.1:1001/A.html
B.html地址为:http://127.0.0.1:002/B.html
Proxy.html地址为:http://127.0.0.1:1002/proxy.html
可以看出B页面和Proxy页面同源,A想访问B的数据就跨域了
B.html的代码,可以看到B.html的window对象上有一个name属性
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><script>// 服务器端需要返回给A的信息都在window.name中存储window.name = "这是B页面的数据";</script></body>
</html>
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><iframeid="iframe"src="http://127.0.0.1:1002/B.html"frameborder="0"style="display: none"></iframe><script>iframe.onload = function () {// 直接读不允许;console.log(iframe.contentWindow.name);};</script></body>
</html>
直接读不允许,控制报跨域错误

将iframe的src属性修改成和B.html同域的Proxy.html地址
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><iframeid="iframe"src="http://127.0.0.1:1002/B.html"frameborder="0"style="display: none"></iframe><script>let count = 0;iframe.onload = function () {// 直接读不允许;// console.log(iframe.contentWindow.name);// 需要我们先把地址重新指向到同源中,才可以// iframe.src = 'http://127.0.0.1:1001/proxy.html';// 只要proxy.html中的window没有name属性,那么这里就会取到B.html中window.name// console.log(iframe.contentWindow.name);if (count === 0) {iframe.src = "http://127.0.0.1:1001/proxy.html";count++;return;}console.log(iframe.contentWindow.name);};</script></body>
</html>
在A.html中成功读取到B.html的数据

9. location.hash + iframe(只做了解)
A和C同源,A和B非同源
A.html
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><iframeid="iframe"src="http://127.0.0.1:1002/B.html"frameborder="0"style="display: none"></iframe><script>let iframe = document.getElementById("iframe");iframe.onload = function () {iframe.src = "http://127.0.0.1:1002/B.html#msg=hello";};// 开放给同域C.html的回调方法function func(res) {console.log(res);}</script></body>
</html>
B.html
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><iframeid="iframe"src="http://127.0.0.1:1001/C.html"frameborder="0"style="display: none"></iframe><script>let iframe = document.getElementById("iframe");// 监听A传来的HASH值改变,再传给C.htmlwindow.onhashchange = function () {iframe.src = "http://127.0.0.1:1001/C.html" + location.hash;};</script></body>
</html>
C.html
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><script>// 监听B传来的Hash值window.onhashchange = function () {// 再通过操作同域A的js回调,将结果传回window.parent.parent.func(location.hash);};</script></body>
</html>
如果还有其他方案,欢迎留言补充。
总结一下:2、3、4、5 我个人觉得是必须要掌握的,因为我在实际的项目开发中都使用过。
相关文章:
跨域的多种方案详解
浏览器的同源策略是为了保护用户的安全,限制了跨域请求。同源策略要求请求的域名、协议和端口必须完全一致,只要有一个不同就会被认为是跨域请求。 本文列举了一些处理跨域请求的解决方案: JSONPCORS跨域资源共享http proxynginx反向代理web…...
Java / Scala - Trie 树简介与应用实现
目录 一.引言 二.Tire 树简介 1.树 Tree 2.二叉搜索树 Binary Search Tree 3.字典树 Trie Tree 3.1 基本概念 3.2 额外信息 3.3 结点实现 3.4 查找与存储 三.Trie 树应用 1.应用场景 2.Java / Scala 实现 2.1 Pom 依赖 2.2 关键词匹配 四.总结 一.引言 Trie 树…...
JS/jQuery 获取 HTTPRequest 请求标头?
场景:在jquery封装的ajax请求中,默认是异步请求。 需要定一个秘钥进行解密,所以只能存放在请求头中。然后需要值的时候去请求头中读取。 注意:dataType设置,根据请求参数的格式设置,如果是加密字符串&…...
Leetcode—2034.股票价格波动【中等】
2023每日刷题(五十二) Leetcode—2034.股票价格波动 算法思想 实现代码 class StockPrice { public:int last 0;multiset<int> total;unordered_map<int, int> m;StockPrice() {}void update(int timestamp, int price) {if(m.count(time…...
【Linux】diff命令使用
diff命令 是一个用于比较两个文件或目录之间差异的命令。它可以显示两个文件之间的行级别差异,并以易于阅读的格式输出结果。 著者 由保罗艾格特、迈克海特尔、大卫海耶斯、理查德史泰尔曼和Len Tower撰写。 diff命令 -Linux手册页 语法 diff [选项] [文件1]…...
讯飞星火认知大模型与软件测试结合,提升软件质量与效率
随着人工智能技术的不断发展,越来越多的企业开始将其应用于软件开发过程中。其中,讯飞星火认知大模型作为一种基于深度学习的自然语言处理技术,已经在语音识别、机器翻译、智能问答等领域取得了显著的成果。而在软件测试领域,讯飞…...
【Flink on k8s】- 4 - 在 Kubernetes 上运行容器
目录 1、准备 k8s 集群环境、Docker 环境 2、启用 kubernetes 2.1 查询 k8s 集群基本状态...
软件重装或系统重装后避免重复踩坑
1. Office软件的坑在于字体又没了 Word字体库默认没有仿宋_GB2312和楷体仿宋_GB2312,需要手动添加。 提供如下两个下载链接,亲测有效: 仿宋_GB2312 楷体_GB2312 安装步骤:解压-复制.ttf文件至C:\Windows\Fonts 持续更新贴~...
【Jmeter】JSON Extractor变量包含转义字符,使用Beanshell脚本来消除
如果使用Jmeter的JSON Extractor提取的变量包含特殊字符,直接引用时会包含转义字符。可以使用Beanshell脚本来进行字符串转换,从而消除这些转义字符。 import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONArray; import com.ali…...
GO设计模式——5、建造者模式(创建型)
目录 建造者模式(Builder Pattern) 建造者模式的核心角色 优缺点 使用场景 注意事项 代码实现 建造者模式(Builder Pattern) 建造者模式(Builder Pattern)是将一个复杂对象的构建与它的表示分离&…...
《LeetCode力扣练习》代码随想录——字符串(反转字符串II---Java)
《LeetCode力扣练习》代码随想录——字符串(反转字符串II—Java) 刷题思路来源于 代码随想录 541. 反转字符串 II 模拟过程 class Solution {public String reverseStr(String s, int k) {if(s.length()1){return s;}char[] chs.toCharArray();for(int i…...
WMMSE方法的使用笔记
标题很帅 原论文的描述WMMSE的简单应用 无线蜂窝通信系统的预编码设计问题中,经常提到用WMMSE方法设计多用户和速率最大化的预编码,其中最为关键的一步是将原和速率最大化问题转化为均方误差最小化问题,从而将问题由非凸变为关于三个新变量的…...
MySQL核心知识点整理大全1-笔记
目录 MySQL 一、MySQL的基本概念 1.数据库 2.表 3.列 4.行 5.主键 6.索引 二、MySQL的安装与配置 1.下载MySQL安装包 2.安装MySQL 3.启动MySQL 4.配置MySQL a.设置监听端口和IP地址 b.设置数据存储路径 c.设置字符集和排序规则 5.测试MySQL 三、MySQL的基本操…...
理解输出电压纹波和噪声:来源与抑制
医疗设备、测试测量仪器等很多应用对电源的纹波和噪声极其敏感。理解输出电压纹波和噪声的产生机制以及测量技术是优化改进电路性能的基础。 1:输出电压纹波 以Buck电路为例,由于寄生参数的影响,实际Buck电路的输出电压并非是稳定干净的直流…...
uni-app 微信小程序之好看的ui登录页面(二)
文章目录 1. 页面效果2. 页面样式代码 更多登录ui页面 uni-app 微信小程序之好看的ui登录页面(一) uni-app 微信小程序之好看的ui登录页面(二) uni-app 微信小程序之好看的ui登录页面(三) uni-app 微信小程…...
Textual Inversion
参考博客1:https://www.bilibili.com/read/cv25430752/...
笙默考试管理系统-MyExamTest----codemirror(47)
笙默考试管理系统-MyExamTest----codemirror(44) 目录 笙默考试管理系统-MyExamTest----codemirror(44) 一、 笙默考试管理系统-MyExamTest----codemirror 二、 笙默考试管理系统-MyExamTest----codemirror 三、 笙默考试…...
JVM中 Minor GC 和 Full GC 的区别
Java中的垃圾回收(Garbage Collection, GC)是自动内存管理的一部分,其主要职责是识别并清除程序中不再使用的对象来释放内存。Java虚拟机(JVM)在运行时进行垃圾回收,主要分为两种类型:Minor GC和…...
二十一章(网络通信)
计算机网络实现了多台计算机间的互联,使得它们彼此之间能够进行数据交流。网络应用程序就是在已连接的不同计算机上运行的程序,这些程序借助于网络协议,相互之间可以交换数据。编写网络应用程序前,首先必须明确所要使用的网络协议…...
[linux运维] 利用zabbix监控linux高危命令并发送告警(基于Zabbix 6)
之前写过一篇是基于zabbix 5.4的实现文章,但是不太详细,最近已经有两个小伙伴在zabbix 6上操作,发现触发器没有str函数,所以更新一下本文,基于zabbix 6 0x01 来看看效果 高危指令出发问题告警: 发出邮件告…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
