深入理解ajax

本文详细介绍了AJAX的核心概念,包括异步JavaScript和XML的结合,以及如何创建动态网页。内容涉及XMLHttpRequest对象的使用,如open()和send()方法,以及处理响应的状态。此外,还探讨了AJAX的GET和POST请求实现,并讨论了超时设定和跨域问题。文中提到了CORS作为解决跨域的一种标准,以及之前的JSONP技术。
摘要由CSDN通过智能技术生成

什么是 AJAX ?

AJAX = 异步 JavaScript 和 XML。

AJAX 是一种用于创建快速动态网页的技术。

通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。

有很多使用 AJAX 的应用程序案例:新浪微博、Google 地图、开心网等等。

不管前端怎么变,由客户端发起的与服务端通信使用最多的还是ajax。因此ajax无比重要,从刚进入前端世界时写的$.get() / $.put(),$.ajax(),到现在lizard框架中mvc中的model层获取数据的方法(实际上也是对$.ajax()进行各种封装)。

XMLHttpRequest 对象

ajax技术的核心就是XMLHttpRequest对象(简称XHR),IE7+、FireFox、Chrom、Safari都支持原生XMLHttpRequest,直接new一个

var xhr = new XMLHttpRequest();

ie7-就没有这么简单啦,但这版本也太老了,做为新时代前端我有权利抛弃它,这篇文章就不赘述了。

XMLHttpRequest用法

在使用XHR对象时要调用的第一个方法是open()。

xhr.open("get",url,false);

第三个参数表示是否发送异步请求,open只是启动一个请求以备发送,只有当调用send()时才会发送请求到服务器。send(方法的参数就是要做为请求主体发送的数据)。

在收到响应后,响应的数据会自动填充XHR对象的属性,相关介绍如下:

  • responseText:响应主体被返回的文本。
  • responseXML:如果响应内容类型是“text/xml”或“application/xml”,这个属性将保存相应数据的XML DOM文档。
  • status:响应的HTTP状态。
  • statusText:HTTP状态说明。

如果是同步请求的话,只需检测status,走成功或者失败方法。

if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
    //成功
}else{
    //失败
}

如果是异步请求的时候我们必须检测XHR对象的readystate 属性该属性表示请求/响应过程的阶段。取值如下:

  • 0:未初始化。尚未调用open()。
  • 1:启动。已调用open(),未调用send()。
  • 2:发送。已调用send(),未收到响应。
  • 3:接收。接到部分响应数据。
  • 4:完成。已经接受到全部数据。

readystatus一变就会触发一次readystatechange事件:

xhr.onreadystatechange = function(){
    if(xhr.readyStatus == 4){
      if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
          //成功
        }else{
          //失败
        } 
    }
}

默认情况下XHR还会发送HTTP头部信息:

  • Accept:浏览器能处理的内容
  • Accept-Charset:浏览器能显示的字符集
  • Accept-Encoding:浏览器能处理的压缩编码
  • Accept-Language:浏览器当前设置的语言
  • connection:浏览器与服务器之间连接的类型
  • cookie:当前页面设置的任何cookie
  • Host:请求所在域
  • Referer:发出页面请求的URI
  • User-Agent:浏览器用户代理字符串

使用setRequestHeader()方法可以设置自定义请求头部信息。头部字段名称和头部字段值做为key,value形式作为参数。用户也可以自定义头部信息,这样在服务器收到请求后可以进行后续操作。

同样的,调用XHR对象的getResponseHeader()传入头部字段名称,或者调用getAllResponseHeaders()可以获取头部信息的字符串。

因此,服务器端返回给客户端的response可以增加额外的、结构化的数据供前端使用。

GET 、POST

get、post请求大家都太熟悉了,大家都知道从请求参数来看get是把参数附在url后面,post是把请求参数作为请求的主体提交。但是成熟的ajax方法内部是如何去实现的呢。以jQuery、zepto.js封装好的api请求参数来看:

url =   options.url || "", //请求的链接
        type = (options.type || "get").toLowerCase(), //请求的方法,默认为get
        data = options.data || null, //请求的数据
        contentType = options.contentType || "", //请求头
        dataType = options.dataType || "", //请求的类型
        async = options.async === undefined && true, //是否异步,默认为true.
        timeOut = options.timeOut, //超时时间。 
        before = options.before || function(){}, //发送之前执行的函数
        error = options.error || function(){}, //错误执行的函数
        success = options.success || function() {}; //请求成功的回调函数

使用者只需要将type值设置为get或post就可指定这次请求是用post方式还是get方式请求。

可是实际上,get请求时,XHR对象的send()方法的参数需要是null,需要我们手动把参数附在url后,如下:

function addUrlParam(url,name,value){
    url += (url.indexOf("?") == -1 ? "?" : "&");
    url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
}

对post请求而言,直接将data格式化一下塞到send的参数中即可

if (data) {
        if (typeof data === "string") {
            data = data.split("&");
            for (var i = 0, len = data.length; i < len; i++) {
                name = data[i].split("=")[0];
                value = data[i].split("=")[1];
                data[i] =  encodeURIComponent(name) + "=" + encodeURIComponent(value);
            }
            data = data.replace("/%20/g", "+");
        } else if (typeof data === "object") {
            var arr = [];
            for (var name in data) {
                var value = data[name].toString();
                name = encodeURIComponent(name);
                value = encodeURIComponent(value);
                arr.push(name + "=" + value);
            }
            data = arr.join("&").replace("/%20/g", "+");
        }
}

另外对post请求来说,因为XHR设计的目的是处理XML,为了服务器端解析时对post发送的数据和提交web表单的请求一视同仁,我们首先需要调用setRequestHeader方法把Content-Type 头部信息设置为application/x-www-form-urlencoded

xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

并且由前端设置请求字符串,当然字符串也要经过前端的处理。

到这里,我们基本上可以实现一个简单的ajax方法,但是如果要运用到实际生产中,这个方法是不健壮的,会有诸多问题。本文标题深入理解ajax,所以还要继续深入下去,逐步完善我们的ajax方法。

超时设定

一个健壮的ajax方法一定是要用户可以自由设定超时时间的。在XMLHttpRequest对象在早期是没有自己的超时方法的,后来W3C推出了XMLHttpRequest 2级规范,向其中添加了格式化数据(formData()),超时设定(timeout)等方法。

经过formData的append方法添加的健值对是可以直接通过send方法发送的,在这里不再赘述。

如果当前浏览器的XHR对象支持timeout的话,我们可以这样设置超时时间:

xhr.onreadystatechange = function(){
    if(xhr.readyStatus == 4){
      try{
       if((xhr.status >= 200 && xhr.status < 300) || xhr.status ==304){
             //成功
           }else{
             //失败
          } 
        } catch(ex) {
             由ontimeout事件处理程序处理
          }
      
    }
}
xhr.timeout = 1000;//单位是毫秒

当然,浏览器稍微老一点我们就得麻烦点,自己用settimeout写个定时器,时间到了以后标志位改变并且调用xhr.abort()方法取消异步请求。

function setTime(callback, script) {
        if (timeOut !== undefined) {
            timeout_flag = setTimeout(function() {
                
                    timeout_bool = true;
                    xhr && xhr.abort();
                
                console.log("timeout");

            }, timeOut);
        }
    }

xhr.onreadystatechange = function() {
            if (xhr.readyState === 4) {
                if (timeOut !== undefined) {
                    //由于执行abort()方法后,有可能触发onreadystatechange事件,
                    //所以设置一个timeout_bool标识,来忽略中止触发的事件。
                    if (timeout_bool) {
                        return;
                    }
                    clearTimeout(timeout_flag);
                }
                if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {

                    success(xhr.responseText);
                } else {
                     error(xhr.status, xhr.statusText);
                }
            }
        };

跨域

跨域安全策略是对由XHR实现的ajax通信的一个主要限制,但是多数情况下我们必须要访问不同域的资源。CORS是w3c定义的关于必须访问跨域资源时,浏览器与服务器应该如何沟通。对于get post请求来说,发送请求时需要附加一个额外的Origin头部,其中包含请求的源信息(协议、域名和端口),以便服务器端根据这个头部信息来决定是否响应。如果服务器端认为这个请求可以接受,那么就会在Access-Control-Allow-Origin投不中回发相同的源信息(可以回发“*”),如果没有这个头或者有这个头但不匹配的话浏览器会驳回请求。

跨域施就算成功请求也是会有一些限制:

  • 不能使用setRequestHeader()设置自定义头
  • 不能发送和接受cookie
  • 调用getAllRequestHeaders()方法会返回空字符串

在CORS之前,出现过一些处理跨域的奇淫技巧,,比如说之前公司(15年)还在使用的jsonp,具体原理是利用script标签没有跨域问题这个特性(准确说是所有带src属性的标签都有这个特性)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

火兰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值