跨域解决方案大全

什么是跨域

注:本文完整示例地址
先来说一个概念就是同源,同源指的是协议,端口,域名全部相同

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

同源策略是处于对用户安全的考虑,如果非同源就会受到以下限制:

  • cookie不能读取

  • dom无法获得

  • ajax请求不能发送

但是事实是经常需要借助非同源来提供数据,所以就需要进行跨域请求。

JSONP

JSONP是指JSON PaddingJSONP是一种非官方跨域数据交换协议,由于scriptsrc属性可以跨域请求,所以JSONP利用的就是浏览器的这个“漏洞”,需要通信时,动态的插入一个script标签。请求的地址一般带有一个callback参数,假设需要请求的地址为http://localhost:666?callback=show,服务端返回的代码一般是show(数据)JSON数据,而show函数恰恰是前台需要用这个数据的函数。JSONP非常的简单易用,自动补全API利用的就是JSONP,下面来看一个例子:

// 前端请求代码
function jsonp (callback) {var script = document.createElement("script"),url = `http://localhost:666?callback=${callback}`;script.setAttribute("src", url);document.querySelector("head").appendChild(script);
}
function show (data) {console.log(`学生姓名为:${data.name},年龄为:${data.age},性别为${data.sex}`);
}
jsonp("show");
// 后端响应代码
const student = {name: "zp1996",age: 20,sex: "male"
};
var callback = url.parse(req.url, true).query.callback;
res.writeHead(200, {"Content-Type": "application/json;charset=utf-8"
});
res.end(`${callback}(${JSON.stringify(student)})`);

JSONP虽说简单易用,但是有一个很大问题,那就是JSONP只能进行get请求

CORS

CORS(跨域资源共享)是由W3C制定的跨站资源分享标准,可以让AJAX实现跨域访问。想要了解跨域的话,首先需要了解下简单请求

  • 请求方式为GET或者POST

  • 假若请求是POST的话,Content-Type必须为下列之一:

    • application/x-www-form-urlencoded

    • multipart/form-data

    • text/plain

  • 不含有自定义头(类似于segmentfault自定义的头X-Hit

对于简单请求的跨域只需要进行一次http请求:

function ajaxPost (url, obj, header) {return new Promise((resolve, reject) => {var xhr = new XMLHttpRequest(),str = '',keys = Object.keys(obj);for (var i = 0, len = keys.length; i < len; i++) {str += `${keys[i]}=${obj[keys[i]]}&`;}str = str.substring(0, str.length - 1);xhr.open('post', url);xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");if (header instanceof Object) {for (var k in header) xhr.setRequestHeader(k, header[k]);}xhr.send(str);xhr.onreadystatechange = function () {if (xhr.readyState === 4) {if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {resolve(xhr.responseText);} else {reject();}}}});
}
ajaxPost("http://localhost:666?page=cors", {name: "zp1996",age: 20,sex: "male"
})
.then((text) => { console.log(text); }, () => { console.log("请求失败"); });// 后端处理
var postData = "";
// 注释下,下面示例后台代码补充在此处
req.on("data", (data) => {postData += data;
});
req.on("end", () => {postData = querystring.parse(postData);res.writeHead(200, {"Access-Control-Allow-Origin": "*","Content-Type": "application/json;charset=utf-8"});if (postData.name === student.name &&Number(postData.age) === student.age &&postData.sex === student.sex) {res.end(`yeah!${postData.name} is a good boy~`);} else {res.end("No!a bad boy~");}
});

打开控制台观察可以发现,Network只是发出了一次请求,但是对于非简单请求来说,需要两次http请求,在真正的请求之前需要进行一次预请求,下图是进行一次预请求的请求/响应:

clipboard.png

观察响应头,可以发现需要多出了两个响应头:

  • Access-Control-Allow-Headers,用来指明在实际的请求中,可以使用那些自定义的http请求头。

  • Access-Control-Max-Age,用来指定此次预请求的结果的有效期,在有效期内则不会发出预请求,有点像缓存的感觉。

当然还有诸如好多这样的响应头,请大家自行搜索了解,这里就不再过多介绍,下面来看下对于非简单请求跨域的代码处理:

// 前端请求代码
ajaxPost("http://localhost:666?page=cors", {name: "zp1996",age: 20,sex: "male"
}, { "X-author": "zp1996" })
.then((text) => { console.log(text); }, () => { console.log("请求失败"); });// 后端处理,补充在简单请求代码注释处
if (req.method === "OPTIONS") {res.writeHead(200, {"Access-Control-Max-Age": 3000,"Access-Control-Allow-Origin": "*","Access-Control-Allow-Headers": "X-author","Content-Type": "application/json;charset=utf-8"});    res.end();return void 0;        
} 

CSS Text Transformation

既然可以利用script的“漏洞”来进行JSONP跨域,那么是不是也可以利用css样式写可以进行跨域请求来进行跨域呢?答案肯定是yes,利用css还有一个好处那就是,当被注入攻击脚本时,css尽管被注入,也不会引起什么大的安全问题,顶多也就是把页面的样式给改变,而js被注入的话,cookie就有可能被盗取等一系列安全问题出现。大牛已经将其做的非常完善,大家可以去star王集鹄(zswang)CSST,这里我就把我所理解给大家简单的分享下:

// 前端代码
const id = "csst",ele = document.querySelector(`#${id}`),head = document.querySelector("head");
function getStyle (ele, prop) {return getComputedStyle(ele, "").getPropertyValue(prop);
}
function loadCss (url) {return new Promise((resolve) => {const link = document.createElement("link");link.setAttribute("rel", "stylesheet");link.setAttribute("type", "text/css");link.setAttribute("href", url);ele.addEventListener("webkitAnimationStart", function () {resolve(getStyle(ele, "content"));});head.appendChild(link);});
}
loadCss(`http://localhost:666?page=data.css&id=${id}`).then((data) => {console.log(data);
});// 后端代码
function cssData (id) {return `@keyframes a{from{}to{color: red;}}#${id} {content: "这种是很好,但是只能传输文本啊";animation: a 2s;}`;
}
res.writeHead(200, {"Content-Type": "text/css"
});
res.end(cssData(query.id));

通过代码可以看出这种实现方式是靠元素的content来拿接收到的数据,所以传输的只能是文本。至于为什么要返回动画?是因为不利用动画,无法来对css脚本加载进行监测,也就无法进行回调(由于谷歌/火狐不支持linkonloadonreadychange,所以利用animationstart事件)。

window.postMessage

window.postMessage 是一个安全的跨源通信的方法。一般情况下,当且仅当执行脚本的页面使用相同的协议(通常都是 http)、相同的端口(http默认使用80端口)和相同的 host(两个页面的 document.domain 的值相同)时,才允许不同页面上的脚本互相访问。 window.postMessage 提供了一个可控的机制来安全地绕过这一限制,当其在正确使用的情况下。

window.postMessage解决的不是浏览器与服务器之间的交互,解决的是浏览器不同的窗口之间的通信问题,可以做的就是同步两个网页,当然这两个网页应该是属于同一个基础域名。

// 发送端代码
var domain = "http://localhost",index = 1,target = window.open(`${domain}/postmessage-target.html`);
function send () {setInterval(() => {target.postMessage(`第${index++}次数据发送`, domain);}, 1000);
}
send();
// 接受端代码
<div id="test">没有数据过来啊<div>
<script type="text/javascript">var test = document.querySelector("#test");window.addEventListener("message", e => {if (e.origin !== "http://localhost") {return void 0;}test.innerText = e.data;});
</script>

上述代码实现了向一个页面向另一个发送数据,但是这么写往往有着一些“危险”,需要知道的是,postMessage是向document对象中,网络连接有时会很慢,可能会出现些问题,所以最好的方式是接受页面已经开始加载了,这时发送一个消息给发送端,发送端在开始向接收端发送数据。改进下:

// 发送端添加代码
window.addEventListener("message", (e) => {if (e.data === "ok")send();else console.log(e.data);
});// 接受端的head里面加上script标签
<script type="text/javascript">opener.postMessage("ok", opener.domain);
</script>

window.name

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

这个方式我基本上没有用过,所以没有过多的发言权,大家想了解这个技术的话,可以通过怿飞(圆心):使用 window.name 解决跨域问题,圆心大神解释的非常透彻。

document.domain

将子域和主域的document.domain设为同一个主域
前提条件:

  • 这两个域名必须属于同一个基础域名

  • 而且所用的协议,端口都要一致,否则无法利用document.domain进行跨域

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

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

相关文章

2013年下半年信息系统项目管理师考试试卷(回忆版)

2013年下半年信息系统项目管理师上午试卷&#xff08;网友回忆版&#xff09;信息系统的生命周期可以分为立项、开发、运维和消亡4个阶段&#xff0c;应在信息系统建设的&#xff08;1&#xff09;考虑系统消亡的条件和时机。&#xff08;1&#xff09;A&#xff0e;初期B&…

酱油和gbt酱油哪个好_酱油可不是越贵越好?看清瓶身上的5个字,教你1分钟买到好酱油...

今天妈妈做饭说酱油用完了&#xff0c;让我去打酱油的地方打5毛钱的酱油&#xff0c;我拿起塑料壶去打酱油&#xff0c;闻起来香香的&#xff0c;一个推自行车的过来&#xff0c;我问他这酱油是勾兑酱油吗&#xff1f;推自行车的小哥&#xff0c;看了我一眼&#xff0c;问我是监…

让 WPF 的 RadioButton 支持再次点击取消选中的功能

让 WPF 的 RadioButton 支持再次点击取消选中的功能目录让 WPF 的 RadioButton 支持再次点击取消选中的功能零、前言一、方法一&#xff1a;后台直接处理二、方法二&#xff1a;提取为自定义控件&#xff08;用户控件&#xff09;三、方法三&#xff1a;附加行为法独立观察员 2…

java数组转换成string_java面试复习重点:类的管理及常用工具,教你抓住面试重点

java复习&#xff1a; 类的管理及常用工具类包写在程序文件的第一行一个Java 源文件中只能声明一个包&#xff0c;且声明语句只能作为源文件的第一条指令导入类能导入非public类&#xff0c;但是不能用因为在其他包缺省的权限用不了package Testp;import Testpackage.*;public …

ubuntu 新建的用户 table 无法补全命令 解决办法

为什么80%的码农都做不了架构师&#xff1f;>>> vi /etc/passwd 用adduser命令新增了用户之后&#xff0c;发现在该新建用户下的命令终端&#xff0c;使用方向键无法调出历史命令&#xff0c;同时tab键也无法补全输入命令。 找到 你新增的用户xxx 修改/bin/bash…

【Unity3D基础】让物体动起来②--UGUI鼠标点击逐帧移动

背景 上一篇通过鼠标移动的代码很简单&#xff0c;所以看的人也不多&#xff0c;但是还是要感谢“武装三藏”在博客园给出的评论和支持&#xff0c;希望他也能看到第二篇&#xff0c;其实可以很简单&#xff0c;而且是精灵自控制&#xff0c;关键是代码少是我喜欢的方式&#x…

一个有趣的Go项目,3D界面管理k8s集群,真好玩!

大家好&#xff0c;我是小碗汤&#xff0c;今天分享一个用Golang开发&#xff0c;很好玩的工具KubeCraftAdmin[1]&#xff1a;用Minecraft方式管理k8s的工具&#xff0c;感兴趣的兄弟不妨玩一玩。文末有视频&#xff0c;供您鉴赏~Minecraft&#xff1a;我的世界&#xff0c;是微…

java 数组拼接_打印Java数组最优雅的方式是什么?这波操作闪瞎我

在 Java 中&#xff0c;数组虽然是一个对象&#xff0c;但并未明确的定义这样一个类&#xff0c;因此也就没有覆盖 toString() 方法的机会。如果尝试直接打印数组的话&#xff0c;输出的结果并不是我们预期的结果。那有没有一些简单可行的方式呢&#xff1f;如果大家也被这个问…

AmazeUI基本样式

2019独角兽企业重金招聘Python工程师标准>>> AmazeUI是一个轻量级、Mobile first的前端框架&#xff0c;基于开源社区流行的前端框架编写。 Normalize AmazeUI使用了normalize.css&#xff0c;但做了些调整&#xff1a;html添加了-webkit-font-smoothing:antialiase…

Oracle基础中的基础视频讲座录像(西安)供免费下载

下载地址播放器也在上述目录中。记得那年园博会&#xff0c;培训中间有一天参观&#xff1a;转载于:https://blog.51cto.com/botang/1323099

她13岁自己造飞机,17岁进麻省理工,3篇黑洞论文被霍金引用......

全世界只有3.14 % 的人关注了爆炸吧知识13岁的时候&#xff0c;你在干嘛&#xff1f;我想&#xff0c;绝大多数人都没有萨布丽娜这么硬核——独自组装飞机。之后&#xff0c;16岁的萨布丽娜完成了生涯首飞&#xff0c;历史第一年轻。17岁时&#xff0c;她考上麻省理工&#xff…

Windows 10 2022 年更新来了!

面向 Release Preview 频道的 Windows 10 预览体验成员&#xff0c;微软现已发布 Windows 10 Build 19044.1499。主要修复1.微软修复了阻止某些环绕声音频在 Microsoft Edge 中播放的问题。2.微软修复了使用中文输入法时&#xff0c;一些应用停止工作的意外错误。3.微软修复了在…

当代成年人的生活状态......

1 小喵咪举起了它的狙击枪▼2 简直有毒...▼3 哈哈哈哈哈▼4 电焊既视感▼5 请问需要小猫咪吗&#xff1f;▼6 哈哈哈哈哈▼7 一物降一物▼7 数学能有多好玩&#xff1f;▼你点的每个赞&#xff0c;我都认真当成了喜欢

c++ why can't class template hide its implementation in cpp file?

类似的问题还有&#xff1a; why cant class template use Handle Class Pattern to hide its implementation? || why there are linker problems (undefined reference) to my class template? 我出现问题的源码&#xff08;见main.cpp,Stack.h,Stack.cpp&#xff09;&…

C# using static 声明

许多实际的扩展可以通过扩展方法来实现&#xff0c;并非所有实际的扩展都有可以扩展的类型。对于某些场景&#xff0c;简单的静态方法比较适合。为了更容易调用这些方法&#xff0c;可以使用 using static 声明除去类名。例如&#xff0c;如果打开了 System.Console using stat…

PHP性能追踪及分析工具xhprof的安装与使用

PHP性能追踪及分析工具xhprof的安装与使用 对于本地开发环境来说&#xff0c;进行性能分析xdebug是够用了&#xff0c;但如果是线上环境的话&#xff0c;xdebug消耗较大&#xff0c;配置也不够灵活&#xff0c;因此线上环境建议使用xhprof进行PHP性能追踪及分析。 我们今天就简…

C 语言 int 型乘法溢出问题

2019独角兽企业重金招聘Python工程师标准>>> long l; int a, b; l a*b; 因为 a*b 的结果仍然以 int 型保存, 所以即使 l 为long,仍然会有溢出,并且截去了部分数据.出现问题. 转载于:https://my.oschina.net/simon203/blog/175885

Android插件化开发基础之Java类加载器与双亲委派模型

类加载器 Java虚拟机类加载过程是把Class类文件加载到内存&#xff0c;并对Class文件中的数据进行校验、转换解析和初始化&#xff0c;最终形成可以被虚拟机直接使用的java类型的过程。 在加载阶段&#xff0c;java虚拟机需要完成以下3件事&#xff1a; a.通过一个类的全限定名…