HTML5中Access-Control-Allow-Origin解决跨域问题

时间:2021-03-19 20:16:32

www.111cn.net 更新:2015-01-07 编辑:flyfox 来源:转载

跨域在开发中一些是一个比较常见的问题虽然有json或者xml来解决,现在html5开始流行了,我们可以通过Access-Control-Allow-Origin解决跨域问题,下面一起来看看。
 

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实现文章阅读进度指示器例子

www.111cn.net 更新:2015-01-03 编辑:angel 来源:转载
下面我们为各位整理一个html5实现文章阅读进度指示器例子,希望这个例子可以帮助到各位。
 
近期我发现很多网站增加了一种能够显示出当前阅读位置的指示器(你阅读了多少依赖于你在这篇文章上向下拉动滚动条拉动了多少)。通常,这种指示器被用在博客的文章或者是长表单上,用于帮助阅读着了解他们还有多少就能完成这篇文章或者表单。

问题

要建立一个阅读位置指示器,我们需要回答如下两个问题:

  1. 网页的长度是多少?网页的长度与文档当前的长度相同,这可以通过javascript计算出来。
  2. 用户当前的阅读位置在哪?要获取用户当前的阅读位置可能需要进入用户的思维中去寻找了,在我们所能处理的给定的技术范围之内,这看起来像是人工智能和不可能实现的。
这让我们不得不去使用一种完全不同的方式去解决这个问题。

原则

这项技术的原则是基于用户不得不滚动滚到条到页面的底部的简单的一个事实。一旦用户滚动滚到条到了页面的底部,我们可以得到用户已经阅读完成了这篇文章。解决获取当前用户阅读位置这个问题的关键看起来就是解决滚动条滚动事件了。

假设用户从页面顶部开始阅读,而且在到达页面底部之前他只会一次性的滚动滚动条,我们将会回答下列问题:
  1. 用户需要滚动多久才能滚到到页面的底部?隐藏在用户视点之下的页面部分实际上就反映了用户需要滚动到页面底部的实际数量。这将成为max属性。
  2. 用户已经滚动了多少部分?这个可以通过文档内容在窗口中的位置到顶部的垂直偏移来进行计算,这个将成为我们的value属性。
HTML5中Access-Control-Allow-Origin解决跨域问题
上图中的例子模拟了用户滚动窗口的行为,当用户向下滚动滚动条的时候,垂直偏移增加。
 
在浏览器的上下文中,document和window是两个不同的对象。window是一个浏览器中可见的区域(在上面例子中蓝色窗口中的部分),document实际上是window中载入的页面(例子中当前滚动的灰色框)。

标记

让我们从最基本的标记开始:

<progress value="0"></progress>
显式的指定value属性是非常重要的。否则,我们的进度条将会处于一个不可知的状态。我们不想给进度条的不可知状态添加不必要的css样式。因此,我们选择通过添加一个初始值以忽略该状态。刚开始,用户从页面的顶部开始阅读,因此,开始值被设置为0,默认情况下,最大的值是1(如果没有指定的话)。
要得到max属性正确的值,我们需要从document高度中减去window的高度。这只能通过javascript来进行处理,我们将在后面的部分再讨论它。
标记在文档中的位置是重度依赖于html文档中剩余元素是怎么放置的。通常,如果你的文档中没有固定位置(fixed)的容器的话,你可以把进度条元素放在body元素内部其它所有元素的顶部。
<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;
}
对于Blink/Webkit/Firefox, 我们需要使用厂商指定的前缀添加到进度条样式上,这里用来给进度条添加颜色。
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来处理与用户之间的交互。

在开始之前,不要忘记在文档中添加jquery的类库。
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
我们需要用jquery去获取进度条元素的max和value属性。
max-它的值是通过document的高度减去window的高度获取的页面未显示出来的部分的高度。
var winHeight = $(window).height(),
  docHeight = $(document).height();
  max = docHeight - winHeight;
$(progress).attr('max', max);
value-刚开始,value属性的值是0(已经在标记中指出了)。然后,随着用户滚动滚动条,垂直方向文档到到窗口的高度将会增加,如果滚动条在页面的最顶部,或者是不可滚动的,偏移将会是0。
var value = $(window).scrollTop();
$(progress).attr('value', value);
提示: 代替使用$(document).height(),我们可以使用诸如section,article,或者是div放置文章的内容进行计算,这样可以获取更高的阅读位置的精确度。当我们的文章含有评论内容和页面的其它组成部分占用了页面超过50%的比例的时候,这一点是非常有用的。
现在,每一次用户滚动滚动条,我们需要重新计算value的值,并设置进度条的value属性。注意的是,max属性是不变的。
$(document).on('scroll', function() {
  value = $(window).scrollTop();
  progressBar.attr('value', value);
});
用户滚动的方向是不重要的,因为我们每次都会重新计算value的值(y方向的偏移)。
我们的代码需要在dom载入之后执行,这一点是非常重要的,否则,过早的计算window/document的高度会产生不可预知的结果。
$(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);
  });
});
(或者是可以让这段代码在页面的底部加载,这样可以跳过使用document的ready调用。

浏览器兼容性

这需要我们建立一个能够在不同浏览器中能够拥有相同表现的阅读位置指示器,我们建立的这个阅读位置指示器能够在所有良好支持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.
这会让进度条的max和value属性都是0。
<progress max="0" value="0"></progress>
因此,我们的进度条仍然是空的,而且我们的背景是透明的,这样页面中就不会出现进度条。这产生一种感觉就是当用户的视点能够充满整个页面的时候,我们没有必要再添加一个指示器了。
而且,因为文档的高度不会超过window的高度,所以滚动事件也是不会被触发的。因此,不需要做任何处理,我们的代码再处理这个边界问题的时候是足够健壮的。

用户改变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移动浏览器本地使用蓝色的进度条作为页面加载进度。现在,如果你在框架上添加一个进度指示器,我保证肯定有很多人需要花费很长时间去理解这个顶部的指示器是有什么作用的。

你必须权衡这个是否对你的用户是有好处的。
 
优点:
  1. 语义准确
  2. 没有引入书math库或者是复杂的计算
  3. 最小化必要的标记
  4. 无缝的兼容不支持html5进度条的浏览器
  5. 无缝的兼容禁用javascript的浏览器
缺点:
  1. 跨浏览器样式是复杂的
  2. 老浏览器的兼容性依赖于传统的div/span(s)标记技术去实现
  3. 性能影响(复杂的dom结构情况下)
  4. 与页面加载进度的进度条容易混淆,让用户很难理解
现在低版本的ie浏览器是不兼容HTML5的,那么我们要如何让它兼职呢?下面来介绍的简单一个IE兼容实现HTML5的placeholder处理办法。
 

只要用过表单中的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>

这个方法我现在在用,而且还是原生的,感觉很不错,推荐给大家。