你应该知道如何跨域

前言

转眼就是秋招季啦。经历了几场笔试面试,屡次被问到关于如何实现跨域。老实说,之前都是纸上谈兵,也没有项目需要跨域,甚至觉得这个东西没什么意义。直到今天项目中遇到了跨域问题,看了不少资料才理解跨域的普遍性和意义。特写此篇文章整理自己所得。

转自个人博客: 关于跨域

什么是跨域

一般来说,如果你在开发中需要进行跨域操作(从一个非同源网站发送请求获取数据),一般而言,你在浏览器控制台看到的结果为:

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.

同源策略

说到跨域就不得不提“同源策略”。

同源策略是Web浏览器针对恶意的代码所进行的措施,为了防止世界被破坏,为了保护世界的和平,Web浏览器,采取了同源策略,只允许脚本读取和所属文档来源相同的窗口和文档的属性。

那么,怎么判断文档来源是否相同呢?很简单,看三个部分: 协议、主机、端口号。只要其中一个部分不同,则不同源。

跨域的应用场景

  1. 来自 home.example.com 的文档里的脚本读取 developer.example.com载入的文档的属性。
  2. 来自 home.example.com 的文档里的脚本读取 text.segmentfault.com载入的文档的属性。

如何跨域

设置domain属性

针对上述应用场景的第一种情况,可以设置Document对象的domain属性。但是设置时使用的字符串必须具有有效的域前缀或者它本身。

PS: domain值中必须有一个点号。

PS: domain不能由松散的变为紧绷的。


  1. //初始值 "home.example.com"  
  2. document.domain = "example.com"; //OK 
  3. document.domain = "home.example.com"; //NO,不能由松散变紧绷 
  4. document.domain = "example"; //NO,必须有一个点号 
  5. document.domain = "another.com"; //NO, 必须是有效域前缀或其本身  

JSONP

JSONP由两部分组成: 回调函数和数据。

原理:通过动态<script>元素来使用,可以通过src属性指定一个跨域URL。


  1. function handler(data){ 
  2.     console.log(data); 
  3.  
  4. var script = document.createElement("script"); 
  5. script.src = "https://segmentfault.com/json/?callback=handler"; 
  6. document.body.insertBefore(script, document.body.firstChild);  

除此之外,还可以利用jQuery来实现。


  1. function jsonCallback(json){ 
  2.   console.log(json); 
  3.  
  4. $.ajax({ 
  5.   url: "http://run.plnkr.co/plunks/v8xyYN64V4nqCshgjKms/data-2.json", 
  6.   dataType: "jsonp" 
  7. }); 

运行结果如下:

某些API(例如Github API)允许你定义一个回调函数,当请求返回时执行该函数。


  1. function logResults(json){ 
  2.   console.log(json); 
  3.  
  4. $.ajax({ 
  5.   url: "https://api.github.com/users/jeresig", 
  6.   dataType: "jsonp", 
  7.   jsonpCallback: "logResults" 
  8. }); 

运行结果如下:

优点:

  1. 兼容性强。
  2. 简单易用,能之间访问响应文本,支持浏览器与服务器之间双向通信。

不足:

  1. 只能用GET方法,不能使用POST方法
  2. 无法判断请求是否失败,没有错误处理。

跨域资源共享CORS

需要浏览器和服务器同时支持。

原理:使用"Origin:"请求头和"Access-Control-Allow-Origin"响应头来扩展HTTP。其实就是利用新的HTTP头部来进行浏览器与服务器之间的沟通。

针对前端代码而言,变化的地方在于相对路径需改为绝对路径。


  1. //以前的方式 
  2. var xhr = new XMLHttpRequest();  
  3. xhr.open("GET", "/test", true);  
  4. xhr.send();  
  5. //CORS方式 
  6. var xhr = new XMLHttpRequest();  
  7. xhr.open("GET", "http://segmentfault.com/test", true);  
  8. xhr.send();   

针对服务器代码而言,需要设置Access-Control-Allow-Origin,显式地列出源或使用通配符来匹配所有源。

优点:

  1. CORS支持所有类型的HTTP请求。
  2. 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据

不足:

  1. 不能发送和接收cookie

更新:服务端可以通过设置Access-Control-Allow-Credentials该字段来表示是否允许发送Cookie。发送ajax请求时,需配置withCredentials属性。(感谢sf小伙伴@lloyd_zhou 指正)

具体可查看 阮一峰大大的博客。

  1. 不能使用setRequestHeader()设置自定义头部
  2. 兼容IE10+

postMessage

postMessge()是HTML5新定义的通信机制。所有主流浏览器都已实现。该API定义在Window对象。


  1. otherWindow.postMessage(message, targetOrigin); 

message: 要传递的消息。

targetOrigin: 指定目标窗口的源。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口;

当源匹配时,调用postMessage()方法时,目标窗口的Window对象会触发一个message事件。在进行监听事件时,应先判断origin属性,忽略来自未知源的消息。


  1. //<http://example.com:8080>上的脚本: 
  2. var popup = window.open(...popup details...); 
  3. popup.postMessage("The user is 'bob' and the password is 'secret'", 
  4.               "https://secure.example.net");   
  5. popup.postMessage("hello there!", "http://example.org"); 
  6.  
  7. function receiveMessage(event) 
  8.   if (event.origin !== "http://example.org") 
  9.     return; 
  10.   // event.source is popup 
  11.   // event.data is "hi there yourself!  the secret response is: rheeeeet!"【见下面一段代码可知】 
  12. window.addEventListener("message", receiveMessage, false);  

针对上面的脚本进行接受数据的操作:


  1. /* 
  2.  * popup的脚本,运行在<http://example.org>: 
  3.  */ 
  4.  
  5. //当postMessage后触发的监听事件 
  6. function receiveMessage(event) 
  7.   //先判断源 
  8.   if (event.origin !== "http://example.com:8080") 
  9.     return; 
  10.  
  11.   // event.source:window.opener 
  12.   // event.data:"hello there!" 
  13.  
  14.   event.source.postMessage("hi there yourself!  the secret response " + 
  15.                            "is: rheeeeet!", 
  16.                            event.origin); 
  17.  
  18. window.addEventListener("message", receiveMessage, false);  

后续

收到了很多小伙伴的建议和指正,不胜感激,我会慢慢丰富这篇文章的内容的。请多多指教~

作者:lsxj

来源:51CTO

时间: 2024-09-19 09:34:12

你应该知道如何跨域的相关文章

快速可扩展的Ajax流代理——提供持续下载跨域数据

简介 由于浏览器禁止跨域的XMLHTTP调用,所有的Ajax网站都必须有一个服务端代理来从外部域比如Flickr或者Digg来抓去内容.对客户端Javascript代码来说,一个XMLHttp的调用将请求传递给宿主在相同域里的服务端代理,然后由代理来从外部服务器上下载内容,并回传给客户端.通常,所有从外部服务器获取内容的Ajax站点都采用这种代理方案,除了一些罕见的使用JSONP的人.当网站上的许多组件正在从外部域下载内容时,这样的代理将会被大量地调用.所以,当代理开始被百万次地调用时,它将变成

Sencha Touch跨域问题解决

之前对于跨域问题仅有粗浅的认识,一般是浏览器层面出于安全性的考虑,不允许调用其他页面的对象.这次在Sencha Touch中解决这个问题额外花掉不少时间. 解决的方法大概就是: 修改服务器的header: JsonP.JsonP方法是一种非官方的解决方案,只支持Get方法,需要服务器端根据callback参数返回不同的内容.返回的内容不是标准的json格式,对服务器端的改动会比较麻烦.我选择了修改服务器返回的header的方法. 1. 修改header的Access-Control-Allow-

java-(HttpClient安全跨域权限问题

问题描述 (HttpClient安全跨域权限问题 用java代码在后台HttpClient请求url,使用跨域时.发现被CAS拦截了.因开发框架使用了CAS校验登录,请求路径时会判断是否登陆.请问一下如何解决CAS拦截后台java代码请求? 解决方案 这个跨域没办法避免.你只能用服务器中转请求,不出现跨域

request参数-jsonp跨域访问Struts2后台,获取到的数据没有用callback参数包裹是怎么回事啊?

问题描述 jsonp跨域访问Struts2后台,获取到的数据没有用callback参数包裹是怎么回事啊? 前端代码: $.ajax({ url:'http://localhost:8080/OA/json/json.action?orgid=aaa&code=00002', dataType:'jsonp', type:"GET", dataFilter:function(json,me){ alert("dataFiter:"+json); }, cont

集中权限管理系统-java 跨域单点登录结合集中权限管理 权限控制采用shiro

问题描述 java 跨域单点登录结合集中权限管理 权限控制采用shiro 这种需求的系统谁做过 之前 参考了 网上博客的 oauth2 但是发现不太符合我这个需求 因为oauth2只是授权 并不能解决 登录集中权限系统后 登录其他网站的问题 现在的需求是 用户权限系统只需要一个系统来 维护其他系统 没有用户系统 统一先通过集中权限系统登录后进行用户角色权限维护 如果先登录其他系统这跳转到集中权限系统进行先登录 而且也不能解决集中权限管理的问题 我想过可能需要redis来 实现这功能 但是 总感觉

Ajax跨域问题解决(Ajax JSONP)

因WEB安全原因,Ajax默认情况下是不能进行跨域请求的,遇到这种问题,自然难不倒可以改变世界的程序猿们,于是JSONP(JSON with Padding)被发明了,其就是对JSON的一种特殊,简单来说就是在原有的JSON数据上做了点手脚,从而达到可以让网页可以跨域请求.在现在互联网技术对"前后分离"大规模应用的时期,JSONP可谓意义重大啊. 假设我们原来的JSON数据为 {"hello":"你好","veryGood":

Ajax跨域查询完美解决通过$.getJSON()实现

原因:浏览器安全上做了限制,禁止ajax跨域获得数据. 解决方法:通过jquery提供的$.getJSON()可以跨域获得JSON格式的数据.优点:兼容性强. Java后台代码: 复制代码 代码如下: protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String callback =req.getParameter("cal

javascript实现跨域的方法汇总

  这篇文章主要给大家汇总介绍了javascript实现跨域的方法的相关资料,需要的朋友可以参考下 由于同源策略的限制,XMLHttpRequest只允许请求当前源(包含域名.协议.端口)的资源. json与jsonp的区别: JSON是一种数据交换格式,而JSONP是一种依靠开发人员创造出的一种非官方跨域数据交互协议. script标签经常被用来加载不同域下的资源,可以绕过同源策略.(有src属性的都可以获取异域文件). 如果请求的这个远程数据本身就是一段可执行的js,那么这些js会被执行(相

JSONP跨域的原理解析及其实现介绍

 JSONP跨域GET请求是一个常用的解决方案,下面我们来看一下JSONP跨域是如何实现的,并且探讨下JSONP跨域的原理 JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为"Same-Origin Policy"(同源策略).这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的文档在同一域下的内容.    JavaScript这个安全策略在进行多if

JS postMessage跨域请求解决方案

    今天看到一篇非常好的文章,忍不住想转载过来,亲自测试了一下,解决了web开发中我们经常遇到最头痛的跨域请求的问题.文章主要是介绍了HTML5 postMessage 和 onmessage API 详细应用,比较长,我只截取了跨域请求解决方案的一部分,想查看全文的人可以去查看原文.   Cross-document messaging 简介 由于同源策略的限制,JavaScript 跨域的问题,一直是一个颇为棘手的问题.HTML5 提供了在网页文档之间互相接收与发送信息的功能.使用这个功