HTML5中Access-Control-Allow-Origin解决跨域问题
www.111cn.net 更新:2015-01-07 编辑:flyfox 来源:转载
A.abc.com 发起一个到 abc.com/B 的ajax请求,也会有跨域的问题。之所以会有跨域问题,实则是因为www.abc.com其实同A.abc.com一样,也是一个二级域名,而非一级域名(一级域名是http://abc.com)。
URL | 说明 | 是否允许通信 |
---|---|---|
http://www.a.com/a.jshttp://www.a.com/b.js | 同一域名下 | 允许 |
http://www.a.com/lab/a.jshttp://www.a.com/script/b.js | 同一域名下不同文件夹 | 允许 |
http://www.a.com:8000/a.jshttp://www.a.com/b.js | 同一域名,不同端口 | 不允许 |
http://www.a.com/a.jshttps://www.a.com/b.js | 同一域名,不同协议 | 不允许 |
http://www.a.com/a.jshttp://170.32.82.74/b.js | 域名和域名对应ip | 不允许 |
http://www.a.com/a.jshttp://script.a.com/b.js | 同一域名,不同二级域名 | 不允许 |
http://www.a.com/a.jshttp://a.com/b.js | 二级域名和一级域名 | 不允许(cookie这种情况下也不允许访问) |
http://www.b.com/a.jshttp://www.a.com/b.js | 不同域名 | 不允许 |
对于是否允许跨域,更详细的说明可以看下表:
有了对跨域的基本概念了解后,就可直接进入这篇文章的主题了。
赞助商链接
解决方法:
若在接收请求的服务端abc.com/B页面用的是php语言,则在页面中加入:
// 指定可信任的域名来接收响应信息,推荐
<?php header('Access-Control-Allow-Origin:http://A.abc.com'); ?>
或加入
// 使用通配符 * ,表示当前服务端通话任何域名发起请求,不推荐
<?php header('Access-Control-Allow-Origin:*'); ?>
就这样在服务端简单加一句响应头responese headers声明,一个跨域请求就不会被浏览器的同源安全策略所阻止了!
用chrome调试工具Network ajax请求查看面板中可以看到,类似如下截图:cors
需要注意的是:
添加响应头responese headers时,允许跨域请求的域名带不带斜杠/还是有区别的,带斜杠/会报错:
XMLHttpRequest cannot load abc.com/B. The 'Access-Control-Allow-Origin' header has a value 'http://A.abc.org/' that is not equal to the supplied origin. Origin 'http://A.abc.org' is therefore not allowed access.
header('Access-Control-Allow-Origin:*');是html5新增的一项标准功能,因此 IE10以下 版本的浏览器是不支持 的,因此,如果要求兼容IE9或更低版本的ie浏览器,会导致使用此种方式的跨域请求以及传递Cookie的计划夭折,最终还得回归JSONP(目前主流的处理方式是使用JSONP,易于实现,兼容性好,可查的资料也很多。)
跨域解决后,如果还要操作Cookie,还得继续补增响应头:
<?php header('Access-Control-Allow-Credentials:true'); ?>
需要将 XMLHttpRequest 对象的 withCredentials 属性设置为 true,JQuery1.5.1+ 就开始提供了相应的字段,使用方式如下:
$.ajax({
url:"B.abc.com",
xhrFields:{
withCredentials:true
},
crossDomain:true
});
哦也~ 收到 Cookie 了。
设置 withCredentials 为 true 的请求中会包含 A.abc.com端的所有Cookie,这些Cookie仍然遵循同源策略,所以,你只能访问其中和 abc.com/B同根域的Cookie,而无法访问其他域的Cookie。
Access-Control-Allow-Origin实则是html5 Cross-Origin Resource Sharing实现的最重要的一点参数配置。
Cross-Origin Resource Sharing,跨域资源共享,简称 CORS,可以作为一种跨域请求以及响应的解决方案。
附:
禁用chrome本地安全策略,不用配服务器环境也能发起ajax请求:
chrome 桌面快捷键 右键属性 在快捷方式标签下的“目标”框中加入 --disable-web-security,重启浏览器即可
html5实现文章阅读进度指示器例子
问题
要建立一个阅读位置指示器,我们需要回答如下两个问题:
-
网页的长度是多少?网页的长度与文档当前的长度相同,这可以通过javascript计算出来。
-
用户当前的阅读位置在哪?要获取用户当前的阅读位置可能需要进入用户的思维中去寻找了,在我们所能处理的给定的技术范围之内,这看起来像是人工智能和不可能实现的。
原则
这项技术的原则是基于用户不得不滚动滚到条到页面的底部的简单的一个事实。一旦用户滚动滚到条到了页面的底部,我们可以得到用户已经阅读完成了这篇文章。解决获取当前用户阅读位置这个问题的关键看起来就是解决滚动条滚动事件了。
-
用户需要滚动多久才能滚到到页面的底部?隐藏在用户视点之下的页面部分实际上就反映了用户需要滚动到页面底部的实际数量。这将成为max属性。
-
用户已经滚动了多少部分?这个可以通过文档内容在窗口中的位置到顶部的垂直偏移来进行计算,这个将成为我们的value属性。
标记
让我们从最基本的标记开始:
<progress value="0"></progress>
<body> <progress value="0"></progress> <!-------------------------------- 这里放额外的标记 ---------------------------------> </body>
为指示器添加样式
我们想要让我们的指示器总是在页面的顶部显示,即使用户滚动窗口也是这样,我们将progress元素设置为fixed。另外,我们应该希望进度条的背景是transparent(透明)的,这样在页面滚动时就不会创建一个空的进度条阻碍用户视线。同时,这也会帮助我们处理好在javascript被禁用的时候浏览器的表现,后面我们会介绍这一点。
progress { /* Positioning */ position: fixed; left: 0; top: 0; /* Dimensions */ width: 100%; height: 5px; /* Reset the appearance */ -webkit-appearance: none; -moz-appearance: none; appearance: none; /* Get rid of the default border in Firefox/Opera. */ border: none; /* Progress bar container for Firefox/IE10+ */ background-color: transparent; /* Progress bar value for IE10+ */ color: red; }
progress::-webkit-progress-bar { background-color: transparent;}progress::-webkit-progress-value { background-color: red; } progress::-moz-progress-bar { background-color: red; }
交互
用javascript计算浏览器的width/height属性是非常麻烦的,同时,在不同内核的浏览器中的表现是非常可怕的。幸运的是,jquery抽象了这些复杂的操作,使得我们可以以清晰的方法去计算window和document的度量。因此,在接下来的内容中,我们将会通过jquery来处理与用户之间的交互。
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
var winHeight = $(window).height(), docHeight = $(document).height(); max = docHeight - winHeight; $(progress).attr('max', max);
var value = $(window).scrollTop(); $(progress).attr('value', value);
$(document).on('scroll', function() { value = $(window).scrollTop(); progressBar.attr('value', value); });
$(document).on('ready', function() { var winHeight = $(window).height(), docHeight = $(document).height(), progressBar = $('progress'), max, value; /* Set the max scrollable area */ max = docHeight - winHeight; progressBar.attr('max', max); $(document).on('scroll', function(){ value = $(window).scrollTop(); progressBar.attr('value', value); }); });
浏览器兼容性
这需要我们建立一个能够在不同浏览器中能够拥有相同表现的阅读位置指示器,我们建立的这个阅读位置指示器能够在所有良好支持html5进度条元素的浏览器中正常工作。但是,这种支持仅在firefox16+,opera 11+, chrome,safari 6+,ie 10+的浏览器上可用。opera 11和12不支持改变进度条的颜色。因此,我们的进度条将会是默认的绿色。
边界问题
在很多情况下,我们上述的代码可能会崩溃或者是不能够正确的指示出用户阅读的位置,让我们看看这些情况。
document高度<=window高度
我们的代码假设了document的高度总是大于window的高度,但是,实际情况并不总是这样的。幸运的是,浏览器会帮助我们处理这种情况,当document的高度比window的高度小的时候,浏览器会返回window的高度。因此,docHeight和winHeight是相同的。
max = docHeight - winHeight; // equal to zero.
<progress max="0" value="0"></progress>
用户改变window的尺寸
当用户改变window的尺寸的时候,window和document的高度将会发生改变。这意味着我们必须要重新计算max和value属性以反映出指示器当前正确的位置。我们将会通过resize事件处理器重新计算正确的位置。
$(window).on('resize', function() { winHeight = $(window).height(), docHeight = $(document).height(); max = docHeight - winHeight; progressBar.attr('max', max); value = $(window).scrollTop(); progressBar.attr('value', value); });
javascript被禁用
当javascript被禁用的时候,我们的进度条将会有一个最大值为1,当前默认值为0。
<progress max="1" value="0"></progress>
旧的浏览器兼容
旧的不支持html5的进度条元素的浏览器将会忽略掉progress标记。然而,对于一些站点来说,提供始终如一的体验是非常重要的(该方案略,详见原文)。
性能
通常,给滚动事件添加事件处理器被认为是非常不好的实践,因为每次滚动的时候,浏览器都会试图去重绘出现的内容。在我们的例子中,dom的结构和样式是比较简单的,在页面滚动的时候不会有任何明显会注意到的延迟或者是滞后。然而,当我们放大这里,在我们的拥有复杂的dom结构的站点中实现的时候,滚动的体验将会是产生很多性能的缺失。
造成的困惑
我不是一个UX专家,但是在一些情况下,我们的指示器的位置和外观可能会是模棱两可的并且会误导用户。ajax驱动的站点比如Medium,Youtube等,使用相似的进度条指示下一个页面载入的进度。Chrome移动浏览器本地使用蓝色的进度条作为页面加载进度。现在,如果你在框架上添加一个进度指示器,我保证肯定有很多人需要花费很长时间去理解这个顶部的指示器是有什么作用的。
-
语义准确
-
没有引入书math库或者是复杂的计算
-
最小化必要的标记
-
无缝的兼容不支持html5进度条的浏览器
-
无缝的兼容禁用javascript的浏览器
-
跨浏览器样式是复杂的
-
老浏览器的兼容性依赖于传统的div/span(s)标记技术去实现
-
性能影响(复杂的dom结构情况下)
-
与页面加载进度的进度条容易混淆,让用户很难理解
只要用过表单中的placeholder的前端同学,就会发现它的强大之处,再也不用写一些超多事件的JS来实现,而这个属性却不能被脑残的IE低版本所支持,我们只能想一些办法来变通一下。
一、JQ方式实现(不支持password类型)
代码如下 | 复制代码 |
<script type="text/javascript"> if( !('placeholder' in document.createElement('input')) ){ $('input[placeholder],textarea[placeholder]').each(function(){ var that = $(this), text= that.attr('placeholder'); if(that.val()===""){ that.val(text).addClass('placeholder'); } that.focus(function(){ if(that.val()===text){ that.val("").removeClass('placeholder'); } }) .blur(function(){ if(that.val()===""){ that.val(text).addClass('placeholder'); } }) .closest('form').submit(function(){ if(that.val() === text){ that.val(''); } }); }); } </script> |
上面的方法缺点就是不能支持password类型的文本框,目前还没有很好的解决办法。
二、使用JQ插件jquery.placeholer.js
Github地址:https://github.com/tonitech/jquery.placeholder.js 引入到页面然后执行下面的代码:
代码如下 | 复制代码 |
<script type="text/javascript"> $(function() { $('input, textarea').placeholder(); }); </script> |
这个方法比较简单,唯一令我不喜欢的是它要求jquery版本1.3到1.8,而我现在在项目中使用的是1.11,所以无奈我没有使用,如果你的项目使用的是1.3-1.8版本的,可以尝试下。
三、原生JS通过Label标签实现
代码如下 | 复制代码 |
<script type="text/javascript"> var funPlaceholder = function(element) { //检测是否需要模拟placeholder var placeholder = ''; if (element && !("placeholder" in document.createElement("input")) && (placeholder = element.getAttribute("placeholder"))) { //当前文本控件是否有id, 没有则创建 var idLabel = element.id ; if (!idLabel) { idLabel = "placeholder_" + new Date().getTime(); element.id = idLabel; } //创建label元素 var eleLabel = document.createElement("label"); eleLabel.htmlFor = idLabel; eleLabel.style.position = "absolute"; //根据文本框实际尺寸修改这里的margin值 eleLabel.style.margin = "8px 0 0 3px"; eleLabel.style.color = "graytext"; eleLabel.style.cursor = "text"; //插入创建的label元素节点 element.parentNode.insertBefore(eleLabel, element); //事件 element.onfocus = function() { eleLabel.innerHTML = ""; }; element.onblur = function() { if (this.value === "") { eleLabel.innerHTML = placeholder; } }; //样式初始化 if (element.value === "") { eleLabel.innerHTML = placeholder; } } }; funPlaceholder(document.getElementsByName("username")[0]); funPlaceholder(document.getElementsByName("password")[0]); </script> |
这个方法我现在在用,而且还是原生的,感觉很不错,推荐给大家。
相关内容
- 2016-08-14前后端分离实践跨域问题
- 2016-03-18js利用iframe实现跨域通信例子
- 2016-03-18js中利用JSONP解决跨域问题
- 2015-12-31jquery ajax跨域用jsonp方式调用web服务的例子
- 2015-11-18js中实现浏览器跨域访问解决方案
- 2015-10-28js中window.opener方法的跨域问题分析
- 2015-10-24jQuery跨域调用Asp.Net Web API的例子
- 2015-09-11js通过window.name页面传值,可以跨域
- 2015-08-22js 跨域IFRAME自适应高度例子