解决跨域问题的8种方案(最新最全)

什么是跨域:

浏览器对于javascript的同源策略的限制,例如http://a.cn下面的js不能调用http://b.cn中的js,对象或数据(因为http://a.cn和http://b.cn是不同域),所以跨域就出现了.

同域:简单的解释就是域名相同,端口相同,协议相同

为什么需要跨域?

在最一开始,我们知道了,跨域只存在于浏览器端。而浏览器为 web 提供访问入口。我们在可以浏览器内打开很多页面。正是这样的开放形态,所以我们需要对他有所限制。就比如林子大了,什么鸟都有,我们需要有一个统一的规范来进行约定才能保障这个安全性。

列举的方法挺多的,在面试的时候,只有回答1-2个就可以了,可以看看前面的简单版的答案。

1.同源策略如下:

  • 特别注意两点:
  • 第一,如果是协议和端口造成的跨域问题“前台”是无能为力的,
  • 第二:在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。
  • “URL的首部”指window.location.protocol +window.location.host,也可以理解为“Domains, protocols and ports must match”。

2. 前端解决跨域问题

一、 document.domain + iframe (只有在主域相同的时候才能使用该方法)

1) 在http://www.a.com/a.html中:

document.domain = 'a.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://www.script.a.com/b.html';
ifr.display = none;
document.body.appendChild(ifr);
ifr.onload = function(){var doc = ifr.contentDocument || ifr.contentWindow.document;//在这里操作doc,也就是b.htmlifr.onload = null;
};

2、在http://www.script.a.com/b.html中:

document.domain = 'a.com'; 

二、 动态创建script

这个没什么好说的,因为script标签不受同源策略的限制。

function loadScript(url, func) {var head = document.head || document.getElementByTagName('head')[0];var script = document.createElement('script');script.src = url;script.onload = script.onreadystatechange = function(){if(!this.readyState || this.readyState=='loaded' || this.readyState=='complete'){func();script.onload = script.onreadystatechange = null;}};head.insertBefore(script, 0);
}
window.baidu = {sug: function(data){console.log(data);}
}
loadScript('http://suggestion.baidu.com/su?wd=w',function(){console.log('loaded')});
//我们请求的内容在哪里?
//我们可以在chorme调试面板的source中看到script引入的内容

三、 location.hash + iframe

原理是利用location.hash来进行传值。

假设域名http://a.com下的文件cs1.html要和http://cnblogs.com域名下的cs2.html传递信息。

1) cs1.html首先创建自动创建一个隐藏的iframe,iframe的src指向http://cnblogs.com域名下的cs2.html页面

2) cs2.html响应请求后再将通过修改cs1.html的hash值来传递数据

3) 同时在cs1.html上加一个定时器,隔一段时间来判断location.hash的值有没有变化,一旦有变化则获取获取hash值

注:由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于http://a.com域名下的一个代理iframe

代码如下:

先是http://a.com下的文件cs1.html文件:

function startRequest(){var ifr = document.createElement('iframe');ifr.style.display = 'none';ifr.src = 'http://www.cnblogs.com/lab/cscript/cs2.html#paramdo';document.body.appendChild(ifr);
}function checkHash() {try {var data = location.hash ? location.hash.substring(1) : '';if (console.log) {console.log('Now the data is '+data);}} catch(e) {};
}
setInterval(checkHash, 2000);

http://cnblogs.com域名下的cs2.html:

//模拟一个简单的参数处理操作
switch(location.hash){case '#paramdo':callBack();break;case '#paramset'://do something……break;
}function callBack(){try {parent.location.hash = 'somedata';} catch (e) {// ie、chrome的安全机制无法修改parent.location.hash,// 所以要利用一个中间的cnblogs域下的代理iframevar ifrproxy = document.createElement('iframe');ifrproxy.style.display = 'none';ifrproxy.src = 'http://a.com/test/cscript/cs3.html#somedata';    // 注意该文件在"a.com"域下document.body.appendChild(ifrproxy);}
}

http://a.com下的域名cs3.html

//因为parent.parent和自身属于同一个域,所以可以改变其location.hash的值
parent.parent.location.hash = self.location.hash.substring(1);

四: window.name + iframe

window.name 的美妙之处:name 值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。

1) 创建http://a.com/cs1.html

2) 创建http://a.com/proxy.html,并加入如下代码

<head><script>function proxy(url, func){var isFirst = true,ifr = document.createElement('iframe'),loadFunc = function(){if(isFirst){ifr.contentWindow.location = 'http://a.com/cs1.html';isFirst = false;}else{func(ifr.contentWindow.name);ifr.contentWindow.close();document.body.removeChild(ifr);ifr.src = '';ifr = null;}};ifr.src = url;ifr.style.display = 'none';if(ifr.attachEvent) ifr.attachEvent('onload', loadFunc);else ifr.onload = loadFunc;document.body.appendChild(iframe);}
</script>
</head>
<body><script>proxy('http://www.baidu.com/', function(data){console.log(data);});</script>
</body>

3 在http://b.com/cs1.html中包含:

<script>window.name = '要传送的内容';
</script>

五: postMessage(HTML5中的XMLHttpRequest Level 2中的API)

1) http://a.com/index.html中的代码:

<iframe id="ifr" src="b.com/index.html"></iframe>
<script type="text/javascript">
window.onload = function() {var ifr = document.getElementById('ifr');var targetOrigin = 'http://b.com';  // 若写成'http://b.com/c/proxy.html'效果一样// 若写成'http://c.com'就不会执行postMessage了ifr.contentWindow.postMessage('I was there!', targetOrigin);
};
</script>

2) http://b.com/index.html中的代码:

<script type="text/javascript">window.addEventListener('message', function(event){// 通过origin属性判断消息来源地址if (event.origin == 'http://a.com') {alert(event.data);    // 弹出"I was there!"alert(event.source);  // 对a.com、index.html中window对象的引用// 但由于同源策略,这里event.source不可以访问window对象}}, false);
</script>


六:CORS【这个我也不知道哈】

CORS背后的思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。

IE中对CORS的实现是xdr

var xdr = new XDomainRequest();
xdr.onload = function(){console.log(xdr.responseText);
}
xdr.open('get', 'http://www.baidu.com');
......
xdr.send(null);

其它浏览器中的实现就在xhr中

var xhr =  new XMLHttpRequest();
xhr.onreadystatechange = function () {if(xhr.readyState == 4){if(xhr.status >= 200 && xhr.status < 304 || xhr.status == 304){console.log(xhr.responseText);}}
}
xhr.open('get', 'http://www.baidu.com');
......
xhr.send(null);

实现跨浏览器的CORS

function createCORS(method, url){var xhr = new XMLHttpRequest();if('withCredentials' in xhr){xhr.open(method, url, true);}else if(typeof XDomainRequest != 'undefined'){var xhr = new XDomainRequest();xhr.open(method, url);}else{xhr = null;}return xhr;
}
var request = createCORS('get', 'http://www.baidu.com');
if(request){request.onload = function(){......};request.send();
}


七:JSONP

JSONP包含两部分:回调函数和数据。

回调函数是当响应到来时要放在当前页面被调用的函数。

数据就是传入回调函数中的json数据,也就是回调函数的参数了。

function handleResponse(response){console.log('The responsed data is: '+response.data);
}
var script = document.createElement('script');
script.src = 'http://www.baidu.com/json/?callback=handleResponse';
document.body.insertBefore(script, document.body.firstChild);
/*handleResonse({"data": "zhe"})*/
//原理如下:
//当我们通过script标签请求时
//后台就会根据相应的参数(json,handleResponse)
//来生成相应的json数据(handleResponse({"data": "zhe"}))
//最后这个返回的json数据(代码)就会被放在当前js文件中被执行
//至此跨域通信完成

jsonp虽然很简单,但是有如下缺点:

1)安全问题(请求代码中可能存在安全隐患)

2)要确定jsonp请求是否失败并不容易

八: web sockets

web sockets是一种浏览器的API,它的目标是在一个单独的持久连接上提供全双工、双向通信。(同源策略对web sockets不适用)

web sockets原理:在JS创建了web socket之后,会有一个HTTP请求发送到浏览器以发起连接。取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为web sockt协议。

只有在支持web socket协议的服务器上才能正常工作。

var socket = new WebSockt('ws://www.baidu.com');//http->ws; https->wss
socket.send('hello WebSockt');
socket.onmessage = function(event){var data = event.data;
}
参考于:
作者:PheonixHkbxoic
链接: https://www.cnblogs.com/PheonixHkbxoic/p/5760838.html

总结

跨域问题在目前后端分离的架构中普遍存在,本文所介绍的这几种方案虽然都能够解决跨域问题,但其实各有优劣。比如Jsonp方式实现起来较为简单,但只支持GET请求方式,在原生JavaScript脚本中使用方便,但是当利用了如Vue.js这种MVVM框架时就有些难以施展了。反向代理的方式无需改动后端代码,但是对于整个系统而言可移植性较差,CORS方式需要后端来积极配合前端实现跨域。总之,没有技术银弹,我们要在实际情形中比较分析,选择最合适的方案。

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

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

相关文章

LeetCode 590. N 叉树的后序遍历

590. N 叉树的后序遍历 给定一个 n 叉树的根节点 root &#xff0c;返回 其节点值的 后序遍历 。 n 叉树 在输入中按层序遍历进行序列化表示&#xff0c;每组子节点由空值 null 分隔&#xff08;请参见示例&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [1,null,…

C桑(Cython)从入门到入土(2): np数组操作对比

C桑(Cython)从入门到入土 2. np数组操作对比 Node sc518 Copy has image data of type unsigned long long实际上, &#x1f446;&#x1f3fb;这个错误是我探索Cython的缘起… code1: Form: 更现代的方法是使用内存视图而不是指针&#xff1a; cdef np.uint32_t[:,:,::1] …

【昕宝爸爸小模块】深入浅出之Java 8中的 Stream

深入浅出之Java 8中的 Stream 一、&#x1f7e2;典型解析1.1 &#x1f7e0;Java 8中的Stream 都能做什么1.2 &#x1f7e0;Stream的创建 二、✅ Stream中间操作2.1 &#x1f7e0;Filter2.2 &#x1f7e0;Map2.3 &#x1f7e0;limit / skip2.4 &#x1f7e0;sorted2.5 &#x1…

CCF模拟题 202309-1 坐标变换(其一)

问题描述 试题编号&#xff1a; 202309-1 试题名称&#xff1a; 坐标变换&#xff08;其一&#xff09; 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 512.0MB 问题描述&#xff1a; 对于平面直角坐标系上的坐标&#xff08;x,y&#xff09;&#xff0c;小P定义了一个包含…

【C#】当重复使用一段代码倒计时时,使用普通类和静态方法,实现简单的封装性、可扩展性、可维护性

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《C#》序列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握。…

程序员找不到工作原因以及解决办法

程序员找不到工作原因以及解决办法 程序员当前就业环境真的很差&#xff0c;所以找工作跳槽一定要讲究方式方法&#xff0c;接下来我讲一下你找不着工作的原因以及解决办法&#xff0c;大家先点赞收藏&#xff0c;内容敏感我怕你刷不到 沟通200个全是未读那就是你的城市没有招聘…

安全强化学习笔记

这里写自定义目录标题 参考资料环境算法CPO 2017 ICMLPCPO 2019 ICLRFOCOPS 2020 NIPSCRPO 2021 ICMLCUP 2022 NIPS TRPO 如何看懂TRPO里所有的数学推导细节? - 小小何先生的回答 - 知乎 参考资料 Safe Reinforcement Learning 安全/约束强化学习路线图&#xff08;Safe RL…

Java的NIO

Java NIO&#xff08;New I/O&#xff0c;新 I/O&#xff09;是 Java 1.4 版本引入的一组用于进行非阻塞 I/O 操作的 API。相比于传统的 Java I/O&#xff08;或称为 IOStream&#xff09;&#xff0c;Java NIO 提供了更为灵活、可扩展和高性能的 I/O 处理方式。 Java NIO 的核…

Python-动态烟花【附完整源码】

烟花代码 运行效果&#xff1a;Python动态烟花代码 import pygame from random import randint from random import uniform from random import choice import math vector pygame.math.Vector2 # 重力变量 gravity vector(0, 0.3) # 控制窗口的大小 DISPLAY_WIDTH DISP…

C#核心--实践小项目(贪吃蛇)

C#核心实践小项目 -- 贪吃蛇 必备知识点--多脚本文件 &#xff08;可观看CSharp核心--52集进行了解&#xff09; 必备知识点--UML类图 必备知识点--七大原则 贪吃蛇 项目展示 控制方向的是&#xff1a;WSAD 确定键是&#xff1a;J 需求分析&#xff08;UML类图&#xff09…

第11章 GUI Page495~496 步骤三十一:另存为别的文件

当前的TrySaveFile(bool hint_on_dirty true)有两个特征无法满足“另存”的需求&#xff1a; 一&#xff0c;TrySaveFile仅在数据为“新”的时候才提问用户输入文件名。而“另存”总是要求用户输入一个文件名&#xff0c;多以它总应该弹出一个文件选择对话框&#xff0c;这也…

【网络安全】【密码学】【北京航空航天大学】实验二、数论基础(中)【C语言和Java实现】

实验二、数论基础&#xff08;中&#xff09; 一、实验内容 1、扩展欧几里得算法&#xff08;Extended Euclid’s Algorithm&#xff09; &#xff08;1&#xff09;、算法原理 已知整数 a , b ,扩展的欧几里得算法可以在求得 a , b 的最大公约数的同时&#xff0c;找到一对…

LeetCode[105] 从前序与中序遍历序列构造二叉树

给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 示例 1: 输入: preorder [3,9,20,15,7], inorder [9,3,15,20,7] 输出: [3,9,20,null,null,15,7] …

使用Java连接MongoDB (6.0.12) 报错

报错&#xff1a; Exception in thread "main" com.mongodb.MongoCommandException: Command failed with error 352: Unsupported OP_QUERY command: create. 上图中“The client driver may require an upgrade”说明了“客户端驱动需要进行升级”&#xff0c;解…

What does `rpm -ivh` do?

rpm -ivh 安装 并 显示安装进度 (–install–verbose–hash) rpm -ivh /media/cdrom/RedHat/RPMS/samba-3.0.10-1.4E.i386.rpm 安装rpm -ivh --relocate //opt/gaim gaim-1.3.0-1.fc4.i386.rpm 指定安装到 /opt/gaim[Ref] rpm -uvh和-ivh有什么区别以及zabbix 安…

使用BeanShell写入内容到文件【JMeter】

一、前言 ​ 在我们日常工作中&#xff0c;可能会遇到需要将请求返回的数据写入到文件中。在我们使用JMeter进行性能测试时&#xff0c;就经常能够遇到这种情况。要想达到这种目的&#xff0c;我们一般采取BeanShell后置处理器来将内容写入到文件。 二、提取 ​ 在目前大多数的…

基于多智能体点对点转换的分布式模型预测控制

matlab2020正常运行 基于多智能体点对点转换的分布式模型预测控制资源-CSDN文库

对于软件测试的认识和了解

对软件测试的认识&#xff1a; 软件测试要求开发人员避免测试自己开发的程序。从心理学角度讲&#xff0c;这是很有道理的。特别是一个相对复杂的系统&#xff0c;开发人员在刚刚开发完成的时候&#xff0c;尚沉浸于对自己设计的回味之中。此时去测试的话往往会侧重于程序本身的…

CSS3简单运用过渡元素(transition)

CSS3过渡 概念&#xff1a;在CSS3中&#xff0c;我们可以使用transition属性将元素的某一个属性从“一个属性值”在指定的时间内平滑地过渡到“另一个属性值”&#xff0c;从而实现动画效果。 CSS3变形&#xff08;transform)呈现的仅仅是一个结果&#xff0c;而CSS过渡&…

WPS - 表格虚线变成实线解决方案(Office 同上)

1、选中表格区域&#xff0c;在表格中选中需要调整为实线的表格区域 2、点击设置单元格格式&#xff0c;鼠标进行右击并点击设置单元格格式选项 3、选择实线&#xff0c;在单元格格式下的边框&#xff0c;调整到实线 4、设置为实线&#xff0c;即可将表格的虚线设置为实线