ajax和comet

一,XMLHttpRequest对象
  IE5是最先引入XHR对象的浏览器,XHR对象是经过MSXML库中的一个ActiveX对象实现的
  使用MSXML库中的XHR对象,编写一个函数以下javascript

  function ceateXHR(){
    if(typeof argument.callee.activeXString != "String"){
      var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],i,len;
      for(i=0;len=versions.length;i<len;i++){
        try{
          new ActiveXObject(versions[i]);
          arguments.callee.activeXString = versions[i];
          break;
        }catch(ex){
          //跳过
        }
      }
    }
    return new ActiveXObject(argument.callee.activeXString);
  }

  IE7+,Firefox,Opera,CHrome和safari中支持原生XHR对象,
  var xhr = new XMLHttpRequest();
  为了兼容以上全部,使用下列函数php

  function createXHR(){
    if(typeof XMLHttpRequest != "undefined"){
      return new XMLHttpRequest();
    }else if(typeof ActiveXobject != "undefined"){
      if(typeof argument.callee.activeXString != "String"){
        var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],i.len;
        for(i=0,len=versions.length;i<len;i++){
          try{
            new ActiveXObject(versions[i]);
            argument.callee.activeXString = versions[i];
            break;
          }catch(ex){
            //跳过
          }
        }  
      }
      return new ActiveXObject(argument.callee.activeXString);
    }else{
      throw new Error("No XHR object available");
    }
  }

  建立对象,var xhr = createXHR();
1,XHR的用法
  open(请求的类型(get或post),请求的URL,是否异步发送的布尔值),
  要点:URL相对于执行代码的当前页面(可使用绝对路径),open方法不会真的发送请求只是启动一个请求以备发送
  send(做为请求主体发送的数据),发送特定的请求,能够传人null,调用函数后请求会被派送到服务器
  若是请求时同步的,js代码会等到服务器响应以后执行,响应的数据会自动填充XHR对象的属性
    responseText:做为响应主体被返回的文本
    responseXML:若是响应的内容类型是text/xml,application/xml,这个属性会保存包含响应数据的XML DOM文档
    status:响应的http状态
    statusText:http状态的说明
  响应后,首先检查status属性,http状态200表示成功,此时responseText属性的内容就绪,内容类型正确的同时,responseXML也能够访问了
  状态304表示请求的资源没有被修改,能够直接使用浏览器中缓存的版本,
  xhr.open("get","example.text",false);
  xhr.send(null);
  if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304){
    alert(xhr.responseText);
  }else{
    alert("Request was unsuccessful:" + xhr.status);
  }
  通常状况下使用异步请求,此时js会继续执行没必要等待服务器的响应,此时检测XHR的readyState属性,属性值以下
  0:未初始化,还没有调用open方法
  1:启动,调用了open方法,未调用send方法
  2,发送,调用了send方法,未接受到响应
  3,接收,接收到部分响应数据
  4,完成,接收到所有的响应数据,并且在客户端使用了
  只要readyState属性的值发生变化就会触发readystatechange事件,能够利用这个事件检测每次状态后的readyState的值
  必须在open()以前指定onreadystatechange事件处理程序才能保证跨浏览器兼容html

  var xhr = createXHR();
  xhr.onreadystatechange = function(){
    if(xhr.readyState == 4){
      if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304{
        alert(xhr.responseText);
      }else{
        alert("Request was unsuccessful:" + xhr.status);
      }
    }
  };
  xhr.open("get","example",true);
  xhr.send(null);

  响应以前调用xhr.abort(),能够取消异步请求,因为内存缘由,不建议重用XHR对象
2,HTTP头部信息
  每一个http请求和响应都会带有相应的头部信息,XHR对象也提供了操做这两种头部信息的方式
  发送XHR请求的同时,会发送下列头部信息
    Accept:浏览器可以处理的内容类型
    Accept-Charset:浏览器可以显示的字符集
    Accept-Encoding:浏览器可以处理的压缩编码
    Accept-Language:浏览器当前设置的语言
    Connection:浏览器与服务器之间链接的类型
    Cookie:当前页面设置的任何cookie
    Host:发送请求的页面所在的域
    Referer:发送请求的页面的URL
    User-Agent:浏览器的用户代理字符串
    setRequestHeader(头部字段的名称,头部字段的值)方法能够自定义设置头部信息,在open和send方法以前调用此方法html5

    var xhr = createXHR();
    xhr.onreadystatechange = function(){
      if(xhr.readyState == 4){
        if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304){
          alert(xhr.reponseText);
        }else{
          alert("Request was unsuccessful :" + xhr.status);
        }
      }
    };
    xhr.open("get","example.php",true);
    xhr.setRequestHeader("MyHeader","MyValue");
    xhr.send(null);

  调用XHR对象的getResponseHeader()方法,传人头部字段名称,能够返回相应的响应头部信息
  getAllResponseHeaders()方法,取得一个包含全部头部信息的长字符串
  var myheader = xhr.getResponseHeader("myHeader");
  var allheader = xhr.getAllResponseHeader();
  服务器端,能够利用头部信息向浏览器发送额外的,结构化的数据,没有自定义的状况下,getAllResponseHeader()方法会返回以下
    Date:sun,14 Nov 2004 18:04:03 GMT
    Server: Apache/1.3.29(Unix)
    Vary:Accept
    X-Powered-By:PHP/4.3.8
    Connection:close
    Content-Type:text/html;charset=iso-8859-1
3,GET请求
  用于向服务器查询某些信息,能够将查询字符串追加到URL末尾,
  查询字符串,每一个参数的名称和值使用encodeURIComponent()进行编码,并且全部名值对使用&分隔
  xhr.open("get","example.php?name1=value&name2=value2",true);
  使用下面函数向现有的URL末尾添加查询字符串参数
  function addURLParam(url,name,value){
    url += (url.indexof("?") == -1 ? "?" : &);
    url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
    return url;
  }
  使用下面函数来构建请求URL示例
  var url = "example.php";
  url = addURLParam(url,"name","Nicholas");
  xhr.open("get",url,true);
4,POST请求
  用于向服务器发送应该被保存的数据,
  post请求将数据做为请求的主体提交,请求的主体能够包含很是多的数据,格式不限
  发送post请求,要向send()方法中传人某些数据,能够是XML DOM文档,可使字符串
  XHR模仿表单提交,首先将Content-type头部信息设置为application/x-www-form-urlencoded,而后以适当的格式建立一个字符串,可使用serialize()     函数来建立字符串
  function submitData(){
    var xhr = createXHR();
    xhr.onreadystatechange = function(){
      if(xhr.readystate == 4){
        if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304){
          alert(xhr.responseText);
        }else{
          alert("Request was unsuccessful:" + xhr.status);
        }
      }
    };
  xhr.open("post","postexample.php",true);
  xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
  var form = document.getElementById("user-info");
  xhr.send(serialize(form));
  }
  php文件经过$_POST取得提交的数据
    <?php
      header("Content-type:text/plain");
      echo <<<EOF
      Name:{$_POST["user-name"]}
      Email:{$_POST['user-email']}
      EOF;
    ?>
  若是不设置Content-type头部信息,那么发送给服务器的数据不会出如今$_POST超级全局变量中,
  要访问一样的数据,使用$HTTP_RAW_POST_DATA
二,XMLHttpRequest2级
1,FormData
  为了实现表单数据的序列化,FormData类型为序列化表单以及建立与表单格式相同的数据
  var data = new FormData();
  data.append("name","Nicholas");
  append()方法接收两个参数,键值对,
  经过向FormData构造函数中传人表单元素,能够用表单元素的数据预先向其中填入键值对
  var data = new FormData(document.forms[0]);
  建立了FormData实例,直接传给XHR的send()方法java

  var xhr = createXHR();
  xhr.onreadystatechange = function(){
    if(xhr.readyState == 4){
      if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304){
        alert(xhr.responseText);
      }else{
        alert("Request was unsuccessful :" + xhr.status);
      }    
    }
  };
  xhr.open("post","postexample.php",true);
  var form = document.getElementById("user-info");
  xhr.send(new FormData(form));

  XHR对象可以识别传人的数据类型是FormData的实例,并配置适当的头部信息
2,超时设定
  XHR对象的timeout属性,表示请求在等待响应多少时间以后就终止,给timeout属性设置一个值,在超过了这个值后,
  就会调用ontimeout事件处理程序web

  var xhr = createXHR();
  xhr.onreadystatechange = function(){
    if(xhr.readyState == 4){
      try{
        if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304){
          alert(xhr.responseText);
        }else{
          alert("Request was unsuccessful:" + xhr.status);
        }
      }catch(ex){
        //假设由ontimeout事件处理程序处理
      }
    }
  };
  xhr.open("get","timeout.php",true);
  xhr.timoeout = 1000;
  xhr.ontimeout = function(){
    alert("Request did not return in a second.");
  };
  xhr.send(null);

3,overrideMimeType()方法
  Firefox最先引入了overrideMimeType()方法,用于重写XHR响应的MIME类型,能够把响应当作XML而非纯文原本处理
  var xhr = createXHR();
  xhr.open("get","text.php",true);
  xhr.overrideMimeType("text/XML");
  xhr.send(null);
三,进度事件
  Progress Events规范定义了与客户端服务器通讯有关的事件
  loadstart:在接收到响应数据的第一个字节时触发
  progress:在接收响应期间持续不断的触发
  error:在请求发生错误时触发
  abort:由于调用abort()方法而终止链接时触发
  load:在接收到完整的响应数据时触发
  loadend:在通讯完成,或者触发了error,abort,load事件后触发(还没有被任何浏览器支持)
1,load事件
  firefox引入了load事件,用于替代readystatechange事件
  响应接收完毕后触发load事件,没有必要去检测readyState属性了,
  onload会接收到event对象,target属性就指向XHR对象,能够访问到XHR对象的全部方法和属性
  对于不支持的浏览器算法

  var xhr = createXHR();
  xhr.onload = function(){
    if((xhr.status >=200 && xhr.status <= 300) || xhr.status == 304){
      alert(xhr.responseText);
    }else{
      alert("Request was unsuccessful:" + xhr.status);
    }
  };
  xhr.open("get","alertEvents.php",true);
  xhr.send(null);

2,progress事件
事件在浏览器接收数据期间周期性触发,
onprogress事件处理程序会接收到一个evnet对象,其target属性是XHR对象
包含额外的三个属性:lengthComputable(进度信息是否可用的布尔值),position(已经接收的字符数),totalSize(根据Content-Length响应头部肯定的预期字节数)chrome

var xhr = createXHR();
xhr.onload = function(){
  if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304){
    alert(xhr.responsText);
  }else{
    alert("Request was unsuccessful" + xhr.status);
  }
};
xhr.onprogress = function(event){
  var divStatus = document.getElementById("status");
  if(event.lengthComputable){
    divStatus.innerHTML = "Recevied " + event.position + "Of" + event.totalSize + "bytes";
  }
};
xhr.open("get","alertEvent.php",true);
xhr.send(null);

四,跨源资源共享(CORS)
  思想是使用自定义的http头部,让浏览器与服务器进行沟通,从而决定请求或响应的成功与否
  请求的origin头部,包含请求页面的源信息(协议,域名,端口),
  若是服务器认为是可接受的,在Origin-Control-Allow-Origin头部中回发相同的源信息,若是是公共资源,能够回发*
1,IE对CORS的实现
  IE8引入XDR类型,相似XHR对象,但能实现安全可靠的跨域通讯,区别以下
  cookie不会随请求发送,也不会随响应返回
  只能设置请求头部信息中的Content-type字段
  不能访问响应头部信息
  只支持GET和POST请求
  XDR使用方法,建立一个XDomainRequest的实例,调用open()方法,再调用send()方法,
  open()方法只接收两个参数,请求类型的UR,XDR请求都是异步的,
  请求返回以后会触发load事件,响应的数据保存在responseText属性中
  var xdr = new XDomainRequest();
  xdr.onload = function(){
    alert(xdr.responseText);
  };
  xdr.open("get","http://www.somewhere-else.com/page/");
  xdr.send(null);
  接收到响应后,只能访问响应的原始文本,没有办法肯定响应的状态代码,只要响应有效就会会触发load事件,
  失败就会触发error事件,遗憾的是,除了错误自己外,没有其余信息可用,所以惟一可以肯定的就是请求未成功,
  检测错误能够指定一个onerror事件处理程序
  var xdr = new XDomainRequest();
  xdr.onload = function(){alert(xdr.responseText)};
  xdr.onerror = function(){alert("An error occurred.")};
  xdr.open("get","http://www.somewhere-else.com/page/");
  xdr.send(null);
  返回请求前调用abrot()方法会终止请求
  一样支持timeout属性和ontimeout事件
  var xdr = new XDomainRequest();
  xdr.onload = function(){alert(xdr.responseText);};
  xdr.onerror = function(){alert("An Error Occurred");};
  xdr.timeout = 1000;
  xdr.ontimeout = function(){alert("Request took too long.");};
  xdr.open("get","http://www.somewhere-else.com/page/");
  xdr.send(null);
  为了支持POST请求,XDR对象提供了contenType属性,用来表示发送数据的格式
  var xdr = new XDomainRequest();
  xdr.onload = function(){};
  xdr.onerror = function(){};
  xdr.open("post","http://www.somewhere-else.com/page/");
  xdr.contentType = "application/x-www-form-urlencoded";
  xdr.send("name1=value1&name2=value2");
2,其余浏览器对CORS的实现
  经过XMLHttpRequest对象实现对CORS的原生支持,请求另外一个域中的资源,使用标准的XHR对象并在open方法中传人绝对的URLjson

  var xhr = createXHR();
  xhr.onreadystatechange = function(){
    if(xhr.readyState == 4){
      if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304){
        alert("xhr.responseText");
      }else{
        alert("Request was unsuccessful:" + xhr.status);
      }
    }
  };
  xhr.open("get","htt://www.somewhere-else.com/page/",true);
  xhr.send(null);

  跨域XHR对象有限制,
  不能使用setRequestHeader()设置自定义头部
  不能发送和接受cookie
  调用getAllResponseHeader()方法总会返回空字符串
3,Preflighted Request
  透明服务器验证机制支持开发人员使用自定义的头部,
  使用下列高级选项来发送请求时,就会向服务器发送一个Preflight请求,使用OPTIONS方法,发送下列头部
    Origin:与简单的请求相同
    Access-Control-Request-Method:请求自身使用的方法
    Access-Control-Request-Header:自定义的头部信息,多个头部用逗号分隔
    Origin:http://www.nczonline.net
    Access-Control-Request-Method:POST
    Access-Control-Request-Header:NCZ
  发送这个请求后,服务器能够决定是否容许这种类型的请求,服务器经过在响应中发送以下头部与浏览器进行沟通
    Access-Control-Allow-Origin:与简单请求相同
    Access-Control-Allow-Method:容许的方法,多个方法以逗号分隔
    Access-Control-Allow-Header:容许的头部,多个头部以逗号分隔
    Access-Control-Max-Age:应该将这个Prefight请求缓存多长时间(秒)
    Access-Control-Allow-Origin:http://www.nczonline.net
    Access-Control-Allow-Method:POST,GET
    Access-COntrol-Allow-Header:NZC
    Access-Control-Max-Age:1728000
  第一次发送这种请求时会多一个http请求
4,带凭据的请求
  默认状况下跨源请求不会提供凭据(cookie,HTTP认证,客户端SSL证实)
  经过将withCredentials属性设置为true,能够指定某个请求应该发送凭据
  若是服务器端接收带凭据的请求,会使用Access-Control-Allow-Credentials:true来响应
  若是服务器的响应中没有这个头部,浏览器就不会把响应交给javascript,responseText中将是空字符串status的值为0,调用onerror事件处理程序
5,跨浏览器的CORS跨域

  function createCORSRequest(method,url){
    var xhr = new XMLHttpRequest();
    if("withCredentials" in xhr){
      xhr.open(method,url,true);
    }else if(typeof XDomainRequest != "undefined"){
      vxhr = new XDomainRequest();
      xhr.open(method,url);
    }else{
      xhr = null;
    }
    return xhr;
  }
  var request = createCORSRequest("get","http://www.somewhere-else.com/page/");
  if(request){
    request.onload = function(){
    //
  };
  request.send();
  }

  firefox,safari,chrome中的XMLHttpRequest对象和IE中XDomainRequest对象相似,共有属性方法以下
  abort(),用于中止正在进行的请求
  onerror(),用于替代onreadystatechange()检测错误
  onload(),用于替代onreadystatechange()检测成功
  responseText(),用于取得响应内容
  send(),用于发送请求
五,其余跨域技术
1,图像Ping
  使用img标签,动态的建立图像,使用onload和onerror事件处理程序来肯定是否接收到了响应
  图形Ping是与服务器进行简单,单向,的跨域通讯的一种方式
  请求的数据经过查询字符串形式发送的,响应的是任意内容,一般是像素图或204响应
  var img = new Image();
  img.onload = img.onerror = function(){};
  img.src = "http://www.example.com/test?name=Nicholas";
  请求从设置src属性那一刻开始,请求中发送了name参数
  图像Ping用于跟踪用户点击页面或动态广告曝光次数,
  两个缺点,只能发送get请求,没法访问服务器的响应文本,只能单向通讯
2,JSONP
  被包含在函数调用中的JSON,
  callback({"name":"Nicholas"});
  JSONP包含两部分,回调函数和数据,回调函数是当响应到来时应该在页面中调用的函数,函数名通常在请求中指定
  数据就是传人回调函数中的JSON数据,例如:http://freegeoip.net/json/?callback=handleResponse,指定的函数名为handleResponse()
  JSONP是经过动态script元素使用的,使用时能够为src属性指定一个跨域URL
  function handleResponse(response){
    alert("you're at IP address" + resopnse.ip + ",which is in" + response.city + "," + response.region_name);
  }
  var script = document.createElement(script);
  script.src="http://freegeoip.net/json/?callback=handleResponse";
  document.body.insertBefore(script,document.body.firstChild);
  能够直接访问响应文本,支持在浏览器与服务器之间双向通讯,但不能保证安全,肯定JSONP请求是否失败不是很容易
  html5给script提供onerror事件处理程序,还没有获得任何任何浏览器支持,为此常经过设置计时器检测指定时间内是否收到了响应
3,Comet
  Ajax是一种从页面向服务器请求数据的技术,Comet是一种服务器向页面推送数据的技术
  Comet可以让信息近乎实时的被推送到页面上,很是适合处理体育比赛的分数和股票报价
  两种实现Comet的方式:长轮询和流
    长轮询:页面发起一个到服务器的请求,而后服务器一直保持链接打开,直到有数据可发送,
    发送完数据以后,浏览器关闭链接,随即又发起一个到服务器的新请求,这一过程在页面打开期间持续不断
    长轮询是服务器等待发送响应后发送数据
  HTTP流:浏览器向服务器发送一个请求,服务器保持链接打开,而后周期性向浏览器发送数据
  DOM浏览器中,经过监听readystatechange事件及检测readyState的值是否为3,利用XHR对象实现流

  function createStreamingClient(url,progress,finished){
    var xhr = new XMLHttpRequest(),received = 0;
    xhr.open("get",url,true);
    xhr.onreadystatechange = function(){
      var result;
      if(xhr.readyState == 3){
        //只取得最新数据并整理计数器
        result = xhr.responseText.substring(received);
        received += result.length;
        //调用progress回调函数
        progress(result);
      }else if(xhr.readyState == 4){
        finished(xhr.responseText);
      }
    };
    xhr.send(null);
    return xhr;
  }
  var client = createStreamingClient("streaming.php",function(data){
    alert("Received:" + data);},function(data){
    alert("Done!");
  });

4,服务器发送事件1)SSE API  建立到服务器的单向链接,服务器经过这个链接能够发送任意数量的数据,  服务器响应的MIME类型必须是text/event-stream,支持长短轮询,和http流  首先建立一个新的EventSource对象,并传进一个入口点:  var source = new EventSource("Myevent.php");url要与建立对象的页面同域  EventSource实例有个readyState属性,0表示正链接到服务器,1表示打开了链接,2表示关闭了链接  还有open事件,在创建链接时触发,message事件,在服务器接收到新事件时触发,error事件,在没法创建链接时触发  服务器发回的数据以字符串形式保存在event.data中  默认状况下,EventSource对象会保持与服务器的活动链接,链接断开会从新链接  强制断开使用close()方法,source.close()2)事件流  服务器事件会经过一个持久的http响应发送,这个响应的MIME类型为text/event-stream  响应的格式为纯文本,最简单的状况是每一个数据项前有data  对于多个连续的以data开头的数据行,将做为多段数据解析,每一个值之间有一个换行分隔符  只有包含data:的数据行后有空行,才会触发messge事件,  经过id:前缀能够给特定的事件指定一个关联的ID,位于data:行前面和后面皆可  设置了ID,EventSource对象会跟踪上一次触发的事件,链接断开时,会向服务器发送一个包含名为last-Event-ID的特殊HTTP头部的请求,以便服务器知道     下一次触发的事件5,Web Socket  在一个单独的持久的链接上提供全双工,双向通讯  一个http请求发送到服务器已发起链接,取得服务器响应后,创建的链接使用http升级从http协议交换为web Socket协议  ws://;wss://  1)Web Socket API  首先实例一个WebSocket对象并传人要链接的URL  var socket = new WebSocket("ws://www.example.com/sever.php");  必须给websocket构造函数传人绝对的URL,  浏览器在实例化websocket对象后,立刻尝试建立链接,readyState属性    WebSocket.OPENING(0):正在创建链接    WebSocket.OPEN(1):已经创建链接    WebSocket.CLOSING(2):正在关闭链接    WebSocket.CLOSE(3):已经关闭链接  没有readystatechange事件,readyState永远是从0开始的  关闭WebSocket,使用close方法  2)发送和接收数据  send()方法  var socke = new WebSocket("ws://www.example.com/server.php");  socket.send("hello world");  websocket只能发送纯文本数据,对于复杂的结构,将数据序列化为JSON字符串,使用stringify()方法  当服务器向客户端发来消息时,WebSocket对象会触发message事件,这个message事件与其余传递消息的协议相似,  也是把返回的数据保存在event.data属性中  socket.onmessage = function(event){    var data = event.data;    //处理数据  }  3)其余事件    open:在成功创建链接时触发    error:在发生错误时触发,链接不能持续    close:在链接关闭时触发  WebSocket对象不支持DOM2级事件监听器,必须使用DOM0级语法分别定义每一个事件处理程序  var socket = new WebSocket("ws://www.example.com/server.php");  socket.onopen = function(){};  socket.onerror = function(){};  socket.onclose = function(){};  只有close事件对象包含额外的三个属性    wasClean:布尔值,表示链接是否已经明确的关闭    code:服务器返回的数据状态码    reason:字符串包含服务器发回的消息6,SSE与Web Socket  SSE,支持单向的从服务器读取数据  WebSocket,支持双向通讯  SEE和XHR组合也能够实现双向通讯六,安全  确保XHR访问的URl安全,通行的作法是验证发送请求者是否有权限访问相应的资源  要求以SSL链接来访问能够经过XHR请求的资源  要求每一次请求都附带通过相应算法计算获得的验证码  要求发送POST而不是GET请求(对CSRF攻击没有做用)  检查来源URL以确保是否可信,(对CSRF攻击没有做用,来源记录很容易伪造)  基于cookie信息进行验证(对CSRF攻击没有做用,容易被伪造)

相关文章
相关标签/搜索