读javascript高级程序设计15-Ajax,CORS,JSONP,Img Ping

平时用惯了jQuery.ajax之类的方法,却时常忽略了它背后的实现,本文是学习了AJAX基础及几种跨域解决方案之后的一些收获。

一、AJAX——XMLHttpRequest

谈起Ajax我们都很熟悉,它的核心对象是XMLHttpRequest(简称XHR)。

1.创建对象:

在ie7及以上版本支持原生的写法创建该对象。

var xhr=new XMLHttpRequest();

2.发送请求:

open(type,url,isasync):第一个参数是请求类型(get,post),第二个参数是要请求的url,第三个参数是bool值表示是否为异步请求。该方法没有真正的发送请求,只是启动了一个请求以备发送。

send(body):该方法用来真正的发送请求,参数是请求真正要发送的数据内容。参数是必填项,即便不需要向服务器发送内容,也要传递参数null。

【备注】在get请求中,如果url结尾有查询字符串,那么必须先对其键和值都要进行encodeURIComponent()编码。

3.响应结果:请求的响应结果会自动复制到xhr对象的属性中。

  • status:响应结果的状态码。
  • statusText:响应结果状态说明。
  • responseText:响应返回的文本结果主体;
  • responseXML:如果响应的内容类型为"text/xml",那么结果会以XML DOM的格式赋值在该属性中。如果请求结果是非XML格式,该属性为null。

4.异步请求

大多数情况下我们都需要使用异步请求,此时可以通过检测请求的readyState来判断请求是否已经完成。实际上,每次readyState属性改变时都会触发一次onstatechange事件。readyState属性有五种取值情况:

  • 0:未初始化,也就是还未调用open()方法;
  • 1:启动,已经调用open()方法,尚未调用send()方法;
  • 2:发送,已经调用send()方法,还未收到响应;
  • 3:接收。已经接收到一部分响应结果数据;
  • 4:完成。已经接收到全部响应数据,可以在客户端调用了(最常用)。

【备注】为了保证浏览器兼容性,需要在调用open()方法之前指定onreadystatechange事件处理程序。

5.自定义HTTP请求头

setRequestHeader(key,value):发送自定义消息头。最常用的场景是在post请求中模拟表单提交:xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

【备注】该方法必须在open()之后send()之前调用。

6.简例 demo1.html:

var obj= document.getElementById("result");
           //创建XHR对象
        var xhr = new XMLHttpRequest();
        //状态变化事件
        xhr.onreadystatechange=function(){
             obj.innerHTML+="readyState:"+xhr.readyState+"<br/>";
             //请求完成
             if(xhr.readyState==4){
                       //响应结果
                       if ((xhr.status==200) || xhr.status == 304){
                            var msg="status:"+xhr.status+"<br/>";
                            msg+="statusText:"+xhr.statusText+"<br/>";
                            msg+="responseText:"+xhr.responseText;
                            obj.innerHTML+=msg;
                       } else {
                           alert("请求失败: " + xhr.status);
                       }
                  }
             }
        //启动请求
        xhr.open("get", "weather.json", true);
        //自定义HTTP头
        xhr.setRequestHeader("testheader","hello");
        //发送请求
        xhr.send(null);

二、XHR进度事件

1.load事件

load事件是在响应结果接收完毕时调用,可以用来简化readystatechange事件。不过,只要浏览器接收到结果就会触发该事件,因此还需要自行判断响应状态status。

xhr.onload=function(){
                       if ((xhr.status==200) || xhr.status == 304){
                            obj.innerHTML+="responseText:"+xhr.responseText;

                       } else {
                           alert("请求失败: " + xhr.status);
                       }
             }

2.progress事件

progress事件会在浏览器接收数据的过程中周期性触发。onprogress事件处理程序可以接收到event对象参数,其中event.targe是xhr对象,它还有三个重要的属性:

  • lengthComputable:布尔值,表示进度是否可用;
  • loaded:已经接收的字节数;
  • total:根据响应头中的Content-Length预期需要接收的总字节数。
xhr.onprogress=function(event){
             if(event.lengthComputable){
                  objstatus.innerHTML=event.loaded+"/"+event.total;
                  }
             }

三、跨域资源共享(CORS)

XHR的一个主要约束是同源策略,即:相同域、相同端口、相同协议,可以通过跨域资源共享CORS(Cross-Origin Resourse Sharing)实现跨域资源共享。其基本思想是通过自定义HTTP头让浏览器与服务器沟通,从而确定是否正常响应。如果服务器允许请求,则在响应头添加"Access-Control-Allow-Origin" 来回发源信息.

1.IE对CORS支持——XDR(XDomainRequest)

IE中使用XDR对象实现CORS,它的使用与XHR对象类似,也是实例化后调用open()和send()方法。不同的是,XDR的open()方法只有两个参数:请求类型和URL。

xhr=new XDomainRequest();
xhr.open(method,url);
xhr.send();

2.其他浏览器支持CORS——原生XHR

大多数浏览器的XHR对象原生支持CORS,只需要在open()方法中传入响应的url即可。

3.跨浏览器支持CORS

综合以上两种情况,可以实现跨浏览器的CORS。检查XHR是否支持CORS的最简单方式是检查 withCredentials属性,然后结合检查XDomainRequest对象是否存在即可。

function createCORSRequest(method,url){
              //创建XHR对象
        var xhr = new XMLHttpRequest();
        //启动请求
        if("withCredentials" in xhr){
             xhr.open(method,url,true);
             }else if(typeof XDomainRequest!=‘undefined‘){
                  xhr=new XDomainRequest();
                  xhr.open(method,url);
                  }else{
                       xhr=null;
                       }
        return xhr;
              }

4.实例

下面看个简单的例子,http://www.jsdemo.com/demoajax/demo3.htm 跨域请求 http://www.othersite.com/weather.ashx 中的数据。这是本地搭建的两个测试站点,demo源码见文章底部。

weather.ashx首先检测来源页面,然后决定是否返回Access-Control-Allow-Origin头。

public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "text/plain";
        string referrer = context.Request.ServerVariables["HTTP_REFERER"];
        if (!string .IsNullOrEmpty(referrer) && referrer.IndexOf( "http://www.jsdemo.com") > -1)
        {
            context.Response.AddHeader( "Access-Control-Allow-Origin" , "http://www.jsdemo.com");
        }
        context.Response.Write( "{\"weather\": \"晴\",\"wind\": \"微风\"}" );
    }

demo3.htm通过CORS方式进行跨域请求,并将结果解析后显示在页面中。

var xhr=createCORSRequest("get","http://www.othersite.com/weather.ashx");
         xhr.onload=function(){
              if(xhr.status==200||xhr.status==304){
                   var result=xhr.responseText;
                   var json=JSON.parse(result);
                   var obj= document.getElementById("result");
                   obj.innerHTML="天气:"+json.weather+";风力:"+json.wind;
                   }
              }
      xhr.send();

四、图像跨域请求

<img>标签是没有跨域限制的,我们可以利用图像标签实现一种简单的、单向的跨域通信。图像ping通常用于跟踪用户点击数和广告曝光次数等。

特点:图像跨域请求只能用于浏览器和服务器之间的单向通信,它只能发送Get请求,而且服务访问服务器的响应内容。

来看个小例子demo4.htm,客户端点击链接时触发跨域请求。

<a href="javascript:void(0);" onclick="Click()">点击我</a>
    <script>
         function Click(){
              var img=new Image();
              img.onload=function(){
                   alert(‘DONE‘);
                   }
                   img.src="http://www.othersite.com/demo4.ashx?r="+Math.random();
              }
    </script>

服务端进行简单的计数,并且发送回一像素大小的图像。客户端接收到该结果后会弹窗提示“DONE”。

public static int Count=0;

public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "text/plain" ;
        Count++;
        context.Response.ContentType = "image/gif" ;
        System.Drawing. Bitmap image = new System.Drawing. Bitmap(1, 1);
        image.Save(context.Response.OutputStream, System.Drawing.Imaging. ImageFormat .Gif);
        context.Response.Write(Count);
    }

五、JSONP跨域请求

1.JSONP结构

JSONP是很常用的一种跨域请求方案,常见的JSONP请求格式如下:

http://www.othersite.com/demo5.ashx?callback=showResult

响应结果看上去就像是包在函数调用中的JSON结构:

showResult({"weather": "晴","wind": "微风"})

JSONP结果由两部分组成:回调函数和数据。回调函数一般是在发起请求时指定的,当响应完成时会在页面中调用的函数;数据当然就是请求返回的JSON数据结果。

2.发起请求:

JSONP原理上是利用了动态<script>标签实现的,通过创建script对象,并且将其src属性设置为跨域请求的url地址。当请求完成后,JSONP响应加载到页面中便立即执行。

<script>
         function showResult(json){
                   var obj= document.getElementById("result");
                   obj.innerHTML="天气:"+json.weather+";风力:"+json.wind;
      }
         var script=document.createElement("script");
         script.src="http://www.othersite.com/demo5.ashx?callback=showResult";
         document.body.insertBefore(script,document.body.firstChild);
    </script>

3.特点:

  • JSONP可以实现浏览器和服务器双向通信,并且能够访问响应中的文本;
  • JSONP是从其他域中加载代码并执行的,需要注意其安全性;
  • JSONP请求结果成败不易确定。

附件:DEMO源码

时间: 2024-10-21 09:20:38

读javascript高级程序设计15-Ajax,CORS,JSONP,Img Ping的相关文章

JavaScript高级程序设计15.pdf

组合继承的问题是会调用2次超类型构造函数 寄生组合式继承 即通过借用构造函数来继承属性,通过原型链的形式来继承方法,思路:不必为了指定子类型的原型而调用超类型的原型,我们所需要的无非是超类型原型的一个副本而已 function inheritPrototype(subType,superType){ var prototype=object(subType.prototype); //创建对象 prototype.constructor=subType; //增强对象 subType.proto

《JAVASCRIPT高级程序设计》Ajax与Comet

Ajax,是Asynchronous JavaScript + XML的简写,这一技术能向服务器请求额外的技术而无需卸载页面,会带给用户更好的体验.Ajax的核心是XMLHttpRequest对象.为了防止XSS(跨站点脚本).CSRF(跨站点请求伪造)等攻击,Ajax有着同源策略的限制:解决跨域的方式有CORS(跨源资源共享).图像Ping和JSONP. Comet是对Ajax的扩展,让服务器向浏览器推送数据,有长轮询和HTTP流两种方式实现. webSocket是一种使用自定义的协议,与服务

[笔记]《JavaScript高级程序设计》- Ajax与Comet

在XHR出现之前,Ajax式的通信必须借助一些hack手段来实现,大多数是使用隐藏的框架或内嵌框架. 一.XMLHttpRequest 对象 1 XHR的用法 在使用XHR对象时,要调用的第一个方法是open(),它接受3个参数:要发送的请求的类型("get"."post"等).请求的URL和表示是否异步发送请求的布尔值. 要发送特定的请求,必须向下面这样调用send()方法.send()方法要接受一个参数,作为请求主体发送的数据.如果不需要通过请求主题发送数据,则

[已读]JavaScript高级程序设计(第3版)

从去年开始看,因为太长,总是没有办法一口气把它看完,再加上它与第二版大部分一致,读起来兴致会更缺一点. 与第二版相比,它最大的改变就是增加了很多html5的内容,譬如:Object对象的一些新东西,数据属性.访问器属性及相应的一些方法;比如它对跨域常见方法的比较和总结:postMessage,IE8的XDR,升级的XHR,jsonp跨域原理,单向的图片ping;又比如对数据推送的一些介绍,长轮询和http流是什么样子,单向的SSE和双向的Web Socket的详细介绍和比较. PS,关于SSE,

读javascript高级程序设计17-在线检测,cookie,子cookie

一.在线状态检测 开发离线应用时,往往在离线状态时把数据存在本地,而在联机状态时再把数据发送到服务器.html5提供了检测在线状态的方法:navigator.onLine和online/offline事件. 1.navigator.onLine属性 表示当前的网络状态是否在线,true表示在线,false表示离线.当网络状态变化时,该属性也会随之变化. 2.online和offline事件 HTML5提供了这两个事件,会在网络状态变化时触发.online在网络由离线变为在线时触发:offline

读Javascript高级程序设计第三版第六章面向对象设计--创建对象

虽然Object构造函数或者对象字面量都可以用来创建单个对象,但是缺点非常明显:使用同一接口创建很多对象,会产生大量重复代码. 工厂模式  1 function CreatePerson(name,age,job){ 2         var o=new Object(); 3         o.name=name; 4         o.age=age; 5         o.job=job; 6         o.sayName=function(){ 7            

读javascript高级程序设计16-几条函数小技巧

内容概要 作用域安全的构造函数 惰性载入函数 函数绑定 函数节流 一.作用域安全的构造函数 我们知道,当使用new操作符调用构造函数时,构造函数内部的this会指向新创建对象的实例. function Person(name){ this.name=name; } var p=new Person('peter'); console.log(p.name);//结果:perter 但是,如果没有使用new操作符,而是将构造函数当作普通函数调用时,this会指向window对象. var p1=P

《JavaScript 高级程序设计》

因为曾经在高中买来<C Primer Plus>和大学买来的<Clean Code>(挑战自己买的英文版的结果就啃了一点)给我一种经典的书都特别厚的一本就够读大半年的感觉.加上刚上大学图便宜买的有关做网站的旧书(应该是 Table 布局和 Dreamweaver 比较火的时代的书,这些书倒是很薄)让我一度认为做网页不就是 table 然后 tr.td 什么的套呗,高大上点不就是 div+CSS 嘛有什么大不了,给我设计好什么网页不都 ok 能做出来么?这种感觉.然后看网络课程,在网

JavaScript高级程序设计(第三版)学习笔记20、21、23章

第20章,JSON JSON(JavaScript Object Notation,JavaScript对象表示法),是JavaScript的一个严格的子集. JSON可表示一下三种类型值: 简单值:字符串,数值,布尔值,null,不支持js特殊值:undefined 对象:一组无序的键值对 数组:一组有序的值的列表 不支持变量,函数或对象实例 注:JSON的字符串必须使用双引号,这是与JavaScript字符串最大的区别 对象 { "name":"Nicholas"