转眼就是秋招季啦。经历了几场笔试面试,多次被问到关于如何实现跨域。老实说,以前都是纸上谈兵,也没有项目须要跨域,甚至以为这个东西没什么意义。直到今天项目中遇到了跨域问题,看了很多资料才理解跨域的广泛性和意义。特写此篇文章整理本身所得。
转自我的博客: 关于跨域html
通常来讲,若是你在开发中须要进行跨域操做(从一个非同源网站发送请求获取数据),通常而言,你在浏览器控制台看到的结果为:前端
XMLHttpRequest cannot load http://external-domain/service. No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://my-domain’ is therefore not allowed access.
git
说到跨域就不得不提“同源策略”。
同源策略是Web浏览器针对恶意的代码所进行的措施,为了防止世界被破坏,为了保护世界的和平,Web浏览器,采起了同源策略,只容许脚本读取和所属文档来源相同的窗口和文档的属性。
那么,怎么判断文档来源是否相同呢?很简单,看三个部分: 协议、主机、端口号。只要其中一个部分不一样,则不一样源。github
来自 home.example.com
的文档里的脚本读取 developer.example.com
载入的文档的属性。面试
来自 home.example.com
的文档里的脚本读取 text.segmentfault.com
载入的文档的属性ajax
domain
属性针对上述应用场景的第一种状况,能够设置Document
对象的domain
属性。可是设置时使用的字符串必须具备有效的域前缀或者它自己。
PS: domain
值中必须有一个点号。
PS: domain
不能由松散的变为紧绷的。json
//初始值 "home.example.com" document.domain = "example.com"; //OK document.domain = "home.example.com"; //NO,不能由松散变紧绷 document.domain = "example"; //NO,必须有一个点号 document.domain = "another.com"; //NO, 必须是有效域前缀或其自己
JSONP由两部分组成: 回调函数和数据。
原理:经过动态<script>
元素来使用,能够经过src
属性指定一个跨域URL。segmentfault
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);
除此以外,还能够利用jQuery
来实现。api
function jsonCallback(json){ console.log(json); } $.ajax({ url: "http://run.plnkr.co/plunks/v8xyYN64V4nqCshgjKms/data-2.json", dataType: "jsonp" });
运行结果以下:跨域
某些API(例如Github API)容许你定义一个回调函数,当请求返回时执行该函数。
function logResults(json){ console.log(json); } $.ajax({ url: "https://api.github.com/users/jeresig", dataType: "jsonp", jsonpCallback: "logResults" });
运行结果以下:
优势:
兼容性强。
简单易用,能之间访问响应文本,支持浏览器与服务器之间双向通讯。
不足:
只能用GET
方法,不能使用POST
方法
没法判断请求是否失败,没有错误处理。
须要浏览器和服务器同时支持。
原理:使用"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
更新:服务端能够经过设置Access-Control-Allow-Credentials
该字段来表示是否容许发送Cookie。发送ajax请求时,需配置withCredentials
属性。(感谢sf小伙伴@lloyd_zhou 指正) 具体可查看 阮一峰大大的博客。
不能使用setRequestHeader()
设置自定义头部
兼容IE10+
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);
收到了不少小伙伴的建议和指正,不胜感激,我会慢慢丰富这篇文章的内容的。请多多指教~