前言
转眼就是秋招季啦。经历了几场笔试面试,屡次被问到关于如何实现跨域。老实说,之前都是纸上谈兵,也没有项目需要跨域,甚至觉得这个东西没什么意义。直到今天项目中遇到了跨域问题,看了不少资料才理解跨域的普遍性和意义。特写此篇文章整理自己所得。
本文来源个人博客: 关于跨域
什么是跨域
同源策略
说到跨域就不得不提“同源策略”。
同源策略是Web浏览器针对恶意的代码所进行的措施,为了防止世界被破坏,为了保护世界的和平,Web浏览器,采取了同源策略,只允许脚本读取和所属文档来源相同的窗口和文档的属性。
那么,怎么判断文档来源是否相同呢?很简单,看三个部分: 协议 、 主机 、 端口号 。只要其中一个部分不同,则不同源。
跨域的应用场景
-
来自
home.example.com
的文档里的脚本读取developer.example.com
载入的文档的属性。 -
来自
home.example.com
的文档里的脚本读取text.segmentfault.com
载入的文档的属性
如何跨域
设置 domain
属性
针对上述应用场景的第一种情况,可以设置 Document
对象的 domain
属性。但是设置时使用的字符串必须具有有效的域前缀或者它本身。
PS: domain
值中必须有一个点号。
PS: domain
不能由松散的变为紧绷的。
//初始值 "home.example.com" document.domain = "example.com"; //OK document.domain = "home.example.com"; //NO,不能由松散变紧绷 document.domain = "example"; //NO,必须有一个点号 document.domain = "another.com"; //NO, 必须是有效域前缀或其本身
JSONP
JSONP由两部分组成: 回调函数和数据。
原理:通过动态 <script>
元素来使用,可以通过 src
属性指定一个跨域URL。
function handler(data){ console.log(data); } var script = document.createElement("script"); script.src = "https://segmentfault.com/json/?callback=handler"; document.body.insertBefore(script, document.body.firstChild);
除此之外,还可以使用 $.ajax
来实现,代码来自于 http://www.tuicool.com/articl...
//通过$.ajax来实现的jsonp $.ajax({ url: 'https://segmentfault.com/json', data: data, dataType: 'jsonp', // jsonp 字段含义为服务器通过什么字段获取回调函数的名称 jsonp: 'callback', // 声明本地回调函数的名称,jquery 默认随机生成一个函数名称 jsonpCallback: 'jsonpCallback', success: function(data) { console.log("ajax success callback: " + data.name) }, error: function(jqXHR, textStatus, errorThrown) { console.log(textStatus + ' ' + errorThrown); } });
优点:
-
兼容性强。
-
简单易用,能之间访问响应文本,支持在浏览器与服务器之间双向通信。
不足:
-
只能用
GET
方法,不能使用POST
方法 -
无法判断请求是否失败,没有错误处理。
跨域资源共享CORS
需要浏览器和服务器同时支持。
原理:使用 "Origin:"
请求头和 "Access-Control-Allow-Origin"
响应头来扩展HTTP。其实就是利用新的HTTP头部来进行浏览器与服务器之间的沟通。
针对前端代码而言,变化的地方在于 相对路径需改为绝对路径 。
//以前的方式 var xhr = new XMLHttpRequest(); xhr.open("GET", "/test", true); xhr.send(); //CORS方式 var xhr = new XMLHttpRequest(); xhr.open("GET", "http://segmentfault.com/test", true); xhr.send();
针对服务器代码而言,需要设置 Access-Control-Allow-Origin
,显式地列出源或使用通配符来匹配所有源。
优点:
-
CORS支持所有类型的HTTP请求。
-
使用CORS,开发者可以使用普通的
XMLHttpRequest
发起请求和获得数据
不足:
-
不能发送和接收
cookie
-
不能使用
setRequestHeader()
设置自定义头部 -
兼容IE10+
postMessage
postMessge()
是HTML5新定义的通信机制。所有主流浏览器都已实现。该API定义在Window对象。
otherWindow.postMessage(message, targetOrigin);
message
: 要传递的消息。
targetOrigin
: 指定 目标窗口
的源。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口;
当源匹配时,调用 postMessage()
方法时,目标窗口的Window对象会触发一个 message
事件。在进行监听事件时,应先判断 origin
属性,忽略来自未知源的消息。
//<http://example.com:8080>上的脚本: var popup = window.open(...popup details...); popup.postMessage("The user is 'bob' and the password is 'secret'", "https://secure.example.net"); popup.postMessage("hello there!", "http://example.org"); function receiveMessage(event) { if (event.origin !== "http://example.org") return; // event.source is popup // event.data is "hi there yourself! the secret response is: rheeeeet!"【见下面一段代码可知】 } window.addEventListener("message", receiveMessage, false);
针对上面的脚本进行接受数据的操作:
/* * popup的脚本,运行在<http://example.org>: */ //当postMessage后触发的监听事件 function receiveMessage(event) { //先判断源 if (event.origin !== "http://example.com:8080") return; // event.source:window.opener // event.data:"hello there!" event.source.postMessage("hi there yourself! the secret response " + "is: rheeeeet!", event.origin); } window.addEventListener("message", receiveMessage, false);
注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。