Ajax 与异步数据传输

基本概念

Ajax 全称是异步的 JavaScript 和 XML 。 经由过程在背景与服务器举行少许数据交换,AJAX 能够使网页完成异步更新。这意味着能够在不从新加载悉数网页的状况下,对网页的某部份举行更新。传统的网页(不运用 AJAX)假如须要更新内容,必需重载悉数网页页面。

Ajax 具有以下长处和瑕玷:

  • 长处
  1. 无需革新页面,用户体验好;
  2. 异步与服务器通讯,不影响主历程,响应更敏捷;
  3. 能够把部份服务器的事变放在客户端的浏览器完成,减轻服务器压力,削减冗余请乞降响应;
  4. Ajax 是前端开辟的标准化手艺,无需插件支撑,跨平台性能好;
  • 瑕玷
  1. Ajax 请求不修正浏览器历史记录,因而不支撑行进退却功用;
  2. Ajax 暴露了过量和服务器交互的细节;
  3. 破坏了顺序的非常机制,轻易调试;
  4. 不利于搜索引擎抓取信息;

同源战略

同源战略是Netscape提出的一个有名的平安战略,它是指同一个“泉源”的数据能够自在接见,但差别源的数据相互之间都不能接见。我们试想一下以下几种状况:

  1. 我们翻开了一个天猫而且登录了本身的账号,这时候我们再翻开一个天猫的商品,我们不须要再举行一次登录就能够直接购置商品,因为这两个网页是同源的,能够同享登录相干的 cookie 或 localStorage 数据;
  2. 假如你正在用支付宝或许网银,同时翻开了一个不知名的网页,假如这个网页能够接见你支付宝或许网银页面的信息,就会发作严峻的平安的题目。明显浏览器不允许如许的事变发作;
  3. 想必你也有过同时上岸好几个 qq 账号的状况,假如同时翻开各自的 qq 空间浏览器会有一个小号形式,也就是别的再翻开一个窗口特地用来翻开第二个 qq 账号的空间。

很明显,第1个和第3个例子中,差别的天猫市肆和 qq 空间属于同源,能够同享登录信息。qq 为了区分差别的 qq 的登录信息,从新翻开了一个窗口,因为浏览器的差别窗口是不能同享信息的。而第2个例子中的支付宝、网银、不知名网站之间黑白同源的,所以彼此之间没法接见信息,假如你执意想请求数据,会提醒非常:

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

那末什么是同源的请求呢?同源请求请求被请求资本页面和发出请求页面满足3个雷同:

协定雷同

域名雷同

端口雷同

简朴明白一下:

/*以下两个数据非同源,因为协定差别*/
http://www.abc123.com.cn/item/a.js
https://www.abc123.com.cn/item/a.js

/*以下两个数据非同源,因为域名差别*/
http://www.abc123.com.cn/item/a.js
http://www.abc123.com/item/a.js

/*以下两个数据非同源,因为主机名差别*/
http://www.abc123.com.cn/item/a.js
http://item.abc123.com.cn/item/a.js

/*以下两个数据非同源,因为协定差别*/
http://www.abc123.com.cn/item/a.js
http://www.abc123.com.cn:8080/item/a.js

/* 以下两个数据非同源,域名和 ip 视为差别源
 * 这里应注重,ip和域名替代一样不是同源的
 * 假定www.abc123.com.cn剖析后的 ip 是 195.155.200.134
 */
http://www.abc123.com.cn/
http://195.155.200.134/

/*以下两个数据同源*/                               /* 这个是同源的*/
http://www.abc123.com.cn/source/a.html
http://www.abc123.com.cn/item/b.js

Ajax

Ajax在编写时一共4个步骤:

  1. 竖立 xhr 对象
  2. 设置传输地点
  3. 设置回调函数
  4. 发送数据

罕见的发送体式格局有 GET 和 POST,除此之外另有 HEAD, DELETE, TRACE, PUT, CONNECT, OPTIONS和 PATCH等,这里只举例前两个 GET 和 POST。

比方依据姓名查询一个人的信息并写在div#output中

//GET 要领
function search(name, fun){
  var xhr = new XMLHttpRequest();
  var url = "search.php?name=" + window.encodeURIComponent(name) + "&t=" + Math.random();
  xhr.open("GET", url);
  xhr.send();
  xhr.onreadystatechange = function(){
    if(xhr.readyState == 4 && xhr.status == 200){
        var data = JSON.parse(xhr.responseText);   //猎取了 JSON 字符串
        fun(data);
    }
  }
}
function show(data){
    this.innerHTML = "姓名:" + data.name + "<br />性别:" + data.gender + "<br />岁数:" + data.age + "<br />地点:" + data.address + "<br />电话:" + data.tel;
}
var output = document.getElementById("output");
search("李华", show.bind(output));

//服务器端 search.php
<?php
 $name = $_GET[name];
 //模拟数据查询效果
 echo '{"name":"' . $name .'","age":18,"gender":"男","tel":"13211112222","address":"北京市海淀区xxxxxxxx"}';
?>
//POST要领
function search(name, fun){
  var xhr = new XMLHttpRequest();
  var url = "search.php";
  var para = "name=" + window.encodeURIComponent(name) + "&t=" + Math.random();
  xhr.open("POST", url);
  //POST体式格局下,必需把 Content-Type 设置为application/x-www-form-urlencoded
  xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  xhr.onreadystatechange = function(){
    if(xhr.readyState == 4 && xhr.status == 200){
      console.log(xhr.responseText);
        var data = JSON.parse(xhr.responseText);   //猎取了 JSON 字符串
        fun(data);
    }
  }
  xhr.send(para);
}
function show(data){
    this.innerHTML = "姓名:" + data.name + "<br />性别:" + data.gender + "<br />岁数:" + data.age + "<br />地点:" + data.address + "<br />电话:" + data.tel;
}
var output = document.getElementById("output");
search("李华", show.bind(output));


//服务器端 search.php
<?php
 $name = $_POST[name];
 //模拟数据查询效果
 echo '{"name":"' . $name .'","age":18,"gender":"男","tel":"13211112222","address":"北京市海淀区xxxxxxxx';
?>

上述代码的 jQuery 写法:

//GET 体式格局
function search(name, fun){
  var url = "search.php?name=" + window.encodeURIComponent(name) + "&t=" + Math.random();
  $.get(url, fun);
}
function show(data){
  data = JSON.parse(data);
    this.innerHTML = "姓名:" + data.name + "<br />性别:" + data.gender + "<br />岁数:" + data.age + "<br />地点:" + data.address + "<br />电话:" + data.tel;
}
var output = document.getElementById("output");
search("李华", show.bind(output));
//POST 体式格局
function search(name, fun){
  var url = "search.php";
  var obj = {};
  obj.name = name;
  obj.t = Math.random();
  $.post(url, obj, fun);
}
function show(data){
  data = JSON.parse(data);
    this.innerHTML = "姓名:" + data.name + "<br />性别:" + data.gender + "<br />岁数:" + data.age + "<br />地点:" + data.address + "<br />电话:" + data.tel;
}
var output = document.getElementById("output");
search("李华", show.bind(output));

Ajax罕见题目

缓存题目

仔细一些能够发明,上面发送请求的数据中加入了一个随机数 t。因为偶然服务器更新的了数据后,我们再一次实行 Ajax 请求不能显现新的效果,这是因为 js 为了加快,页面会运用缓存坚持当前挪用的雷同链接。我们加了一个随机数今后,每次请求差别,浏览器就不会运用缓存数据了。

中文乱码题目

返回的中文数据乱码是因为 js 页面和action页面中运用了差别的编码体式格局致使的。能够有以下2中体式格局处置惩罚(浏览器 html 文件是 urf-8 编码的):

  1. 对请求数据字段举行2次 encodeURI 编码,服务器猎取数据后做一次 UTF-8 转码
  2. 对请求数据字段举行1次 encodeURI 编码,服务器猎取数据后做一次 ISO-8859-1 转换 和一次 UTF-8 转码

tips: 考虑到兼容性,第1个要领更好

兼容性题目

之前的代码并没有按兼容性的花样誊写,不过 Ajax 的兼容也不难,重要表如今 XMLHTTPRequest对象猎取环节:

var xhr;
if(XMLHttpRequest){
  xhr = new XMLHttpRequest();    //chrome, safari, opera, firefox
} else if(ActionXObject){
  try{
    xhr = new ActionXObject("Msxml2.XMLHTTP");   //IE 中 Msxml 插件
  }catch(e){
    xhr = new ActionXObject("Microsoft.XMLHTTP");   //IE
  }
}

GET和POST体式格局对照

GETPOST
退却/革新无害数据会从新提交
书签可藏为书签没法藏为书签
缓存能够缓存不能够缓存
MIME范例application/x-www-from-urlencodeapplication/x-www-from-urlencode或 multipart/form-data (二进制为多重编码
历史记录参数保留在历史记录中参数不会留在历史记录
数据长度URL最长2048个字符(2kB)无穷
数据范例ASCII字符无穷
平安性
可见性数据可见数据不可见

跨域数据接见

JSONP

这里须要强调的是,jsonp不属于Ajax的部份,它只是吧url放入script标签中完成的数据传输,重要长处是不受同源战略限定。因为平常库也会把它和Ajax封装在一同,所以这里放在一同议论。下面是一个jsonp的例子(完胜利用:输入手机号码查询归属地和运营商):

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>兼容题目</title>
    
</head>
<body>
<form>
    <input type="text" name="tel" id="tel" />
    <input type="button" value="search" id="search"/>
    <br/>
</form>
<div id="output"></div>
</body>

<script>
    function jsonpCallback(data) {
        document.getElementById('output').innerHTML = data.province + " " + data.catName;
    } 
    document.getElementById('search').onclick = function(){
        var num = document.getElementById('tel').value;
        if(/^1[34578]\d{9}$/.test(num)){
            var url = "http://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=" + num + "t=" + Math.random() + "&callback=jsonpCallback";   
            var JSONP=document.createElement("script");    
            JSONP.type="text/javascript";    
            JSONP.src= url;    
            document.getElementsByTagName("head")[0].appendChild(JSONP);
        } else {
            alert("您输入的手机号有误")
        }
    };
</script>
</html>

上述代码的悉数js部份能够用jQuery完成,以下:

function jsonpCallback(data) {        
    $('#output').text(data.province + " " + data.catName);    
}
$('#search').click(function(){
    var num = $('#tel').val();
    if(/^1[34578]\d{9}$/.test(num)){
        var url = "http://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=" + num" + "t=" + Math.random();   
        $.ajax({
            url: url, 
            type: 'GET', 
            dataType: 'JSONP',  // 处置惩罚Ajax跨域题目(实质已不是Ajax)
            success: function(data){ 
                $('#output').text(data.province + " " + data.catName);
            }
        });
    } else {
        alert("您输入的手机号有误")
    }
});

其他 Ajax 参数及要领

  • javascript
//属性
xhr.responseText;   //从服务器返回的字符串数据
xhr.responseXML;   //从服务器返回的 XML 数据
xhr.status;    //服务器响应状况
xhr.readyState;    //0: 请求未初始化; 1: 已竖立衔接; 2: 请求已吸收; 3: 请求处置惩罚中; 4: 响应已停当
xhr.timeout;    //指定若干毫秒后超时,长整型
xhr.upload;    //猎取上传进度
xhr.withCredentials;    //是不是能够跨源,boolean 型,默许 false
//要领
xhr.getResponseHeader('connection');   //猎取指定头信息
xhr.getAllResponseHeaders();   //获悉数定头信息
xhr.open("METHOD", url, isAsyn);   //open要领有3个参数,末了一个参数是 Boolean 型,示意是不是异步,默许为 true
xhr.abort();   //停止请求,置xhr.readyState为0,但不触发onreadystatechange
xhr.overrideMimeType()   //强迫重写 http 头的 MIME 范例
//事宜
XMLHttpRequestEventTarget.onreadystatechange   //在xhr.readyState属性转变时触发
XMLHttpRequestEventTarget.ontimeout   //在响应超常常触发
XMLHttpRequestEventTarget.onabort   //当请求失利时挪用该要领
XMLHttpRequestEventTarget.onerror   //当请求发作毛病时挪用该要领
XMLHttpRequestEventTarget.onload   //当一个HTTP请求准确加载出内容后返回时挪用。
XMLHttpRequestEventTarget.onloadstart   //当一个HTTP请求最先加载数据时挪用。
XMLHttpRequestEventTarget.onloadend   //当内容加载完成,不论失利与否,都邑挪用该要领
XMLHttpRequestEventTarget.onprogress   //间歇挪用该要领用来猎取请求过程当中的信息。

注:关于 xhr.status 能够的返回值,详见 http状况码

jQuery 中的 Ajax 要领

ajax 静态要领

$.ajax({options})    //提议一个 ajax 请求
options 经常使用以下属性设置:url, method("GET"/"POST"), crossDomain, accepts(可接受的范例), dataType, cache, contentType(编码花样), success, error等
$.ajaxSetup({options});    //options同上,设置 ajax 默许参数,不发起运用
$.post(url, data, success, datatype);    //提议一个 POST 请求 data为通报参数(可选), success(reponseText, statusText, xhr)  为胜利时的回调函数(可选), datatype(xml/html/script/json/jsonp/text,可选)
$.get(url, data, success, datatype);    //提议一个 GET 请求, 参数同上
$.getScript(url, data, success)    //以 GET 请求猎取一个 JS 文件并实行,参数寄义同上
$.getJSON(url, data, success)    //以 GET 请求猎取一个 JSON 字符串,参数寄义同上

ajax 动态要领

$().ajaxComplete(function(){});    //注册Ajax请求完成时要挪用的处置惩罚顺序
$().ajaxError(function(){});    //注册要在Ajax请求完成时碰到毛病而挪用的处置惩罚顺序
$().ajaxSend(function(){});    //附加要在发送Ajax请求之前实行的函数
$().ajaxStart(function(){});    //注册在第一个Ajax请求最先时要挪用的处置惩罚顺序
$().ajaxStop(function(){});    //注册要在一切Ajax请求完成后挪用的处置惩罚顺序
$().ajaxSuccess(function(){});    //附加要在Ajax请求胜利完成时实行的函数
$().load(url, data, callback);    //返回某 url 的数据,data为通报参数(可选), callback(reponseText, statusText, xhr) 回调函数(可选)

其他相干要领

$.param(obj);    //将对象转化为一个 url 参数列表
$(form).serialize();    //表单数据序列化为 url 参数列表
$(form).serializeArray();    //同上,但返回 JSON 串

简朴封装 Ajax 相干要领

简朴模拟 jQuery 中 $.ajax() 要领

(function(){
  // Ajax 选项
  var options = {
    type: "GET",   //提交体式格局
    url: "",    //途径
    params: {},   //请求参数
    dataType: "text",   //内容范例
    success: function(){},   //回调函数
    error: function(){}
  };

  //猎取 XMLHTTPRequest 对象
  var createRequest = function(){
    var xmlhttp;
    if(xmlhttp.XMLHttpRequest){
      xmlhttp = new XMLHttpRequest();
    }
    else{
      xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
    }
    if(xmlhttp.overrideMimeType){
      xmlhttp.overrideMimeType('text/xml');  //修正 MIME 范例
    }
    return xmlhttp;
  },

  // 设定 Ajax 选项
  var setOptions = function(newOptions){
    for(var prop in newOptions){
      if(newOptions.hasOwnProperty(prop)){
        this.option[prop] = newOptions[prop];
      }
    }
  },

  //花样化参数列表
  var formatParameters = function(){
    var paramsArr = [];
    var params = this.options.params;
    for(var prop in params){
      if(params.hasOwnProperty(prop)){
        paramsArr.push(prop + "=" + encodeURIComponent(params[prop]));
      }
    }
    return paramsArr.join('&');
  },

  //预处置惩罚并挪用响应函数
  var readystatechange = function(xmlhttp){
    var returnValue;
    if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
      switch(this.options.dataType){
        case 'xml':
          returnValue = xmlhttp.responseXML;
          break;
        case 'json':
          returnVaue = xmlhttp.responseText;
          if(returnValue){
            returnValue = eval("(" + returnValue + ")");
          }
          break;
        default:
          returnVaue = xmlhttp.responseText;
          break;
      }
      if(returnValue){
        this.options.success(returnValue);
      }
      else{
        this.options.success();
      }
    } else{
      this.options.error();
    }
  },

  //发送请求,也就是$.ajax()函数
  var request = function(options){
    // var ajaxObj = this;

    var xmlhttp = this.createRequest();
    this.setOptions(options);
    xmlhttp.onreadystatechange = this.readystatechange.bind(null, xmlhttp);

    var formatParams = this.formatParameters();
    var type = this.options.type;
    var url = this.options.url;

    if("GET" === type.toUpperCase()){
      url += "?" + formatParameters;
    }
      xmlhttp.open(type, url, true);

    if("GET" === type.toUpperCase()){
      xmlhttp.send();
    } else if("POST" === type.toUpperCase()){
      xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      xmlhttp.send(formatParameters);
    }
  }

  window.$.ajax = request;  //暴露要领到闭包表面去
})();
    原文作者:Faremax
    原文地址: https://segmentfault.com/a/1190000016286733
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞