zoukankan      html  css  js  c++  java
  • 读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);

    Image

    Image(1)

    二、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();

    3

    四、图像跨域请求

    <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源码

  • 相关阅读:
    mongodb 条件查询
    node 创建静态web服务器(下)(处理异步获取数据的两种方式)
    node 创建静态web服务器(上)
    node.js 从文件流中读写数据及管道流
    node.js 中的 fs (文件)模块
    vue-router 嵌套路由
    (转载)js调用打印机 打印整体或部分
    web react面试题
    vue 面试题
    vue 父页面中含子页面滑动,滑动结束,底部组件进行滑动
  • 原文地址:https://www.cnblogs.com/janes/p/3968781.html
Copyright © 2011-2022 走看看