通过上一篇文章,我们对Ajax有了大概的了解, 接下来再进一步剖析, 首先我们先理解好下面几个概念及其过程:
网页浏览过程分析
一个完整的HTTP请求过程,通常有下面7个步骤
1、建立TCP连接
2、Web浏览器向Web服务器发送请求命令
3、Web浏览器发送请求头信息
4、Web服务器- 应答
5、Web服务器- 发送应答头信息
6、Web服务器- 向浏览器发送数据
7、Web服务器- 关闭TCP连接
Ajax原理
理解同步和异步(基本都用异步请求).
- 同步: 客户端发起请求–等待–>服务器端处理—等待–>响应–>页面载入 (请求错误时全部重新载入)。
- 异步: 客户端发起请求—>服务器端处理—>响应—>页面载入(填写时,即时更新,部分返回)。
注: 其它详情请看前一篇博文
HTTP请求
一个HTTP请求一般由四部分组成
HTTP请求的方法或动作(一般是get或者post)
正在请求的URL
请求头(包含一些客户端环境信息,身份验证信息等)
请求体(请求正文,请求正文中可以包含客户端提交的查询字符串信息,表单信息等等)

HTTP响应
一个HTTP响应一般由三部分组成:
状态码(由数字组成,用来显示请求是成功还是失败)
响应头(响应头和请求头一样包含许多有用的信息,例如服务器类型,日期时间,内容类型和长度等)
响应体(也就是响应正文).

常见的HTTP请求方式
| GET | POST | 
| 用于信息获取/查询(如:浏览帖子) | 用于修改服务器上的资源(如:用户注册) | 
| 安全性低(使用url传递参数所有人可见) | 安全性一般(至少不可见) | 
| 容量低(2000个字符) | 容量几乎无限 | 
常见的HTTP状态码
| 状态码 | 描述 | 原因短语 | 
| 200 | 请求成功.一般用于GET和POST方法 | OK | 
| 301 | 资源移动.所请求资源移动到新的URL,浏览器自动跳转到新的URL | Moved Permanently | 
| 304 | 未修改.所请求资源未修改读取缓存数据 | Not Modified | 
| 400 | 请求语法错误,服务器无法理解 | Bad Request | 
| 404 | 未找到资源,可以设置个性”404页面” | Not Found | 
| 500 | 服务器内部错误 | internal Server Error | 
编写Ajax
类比打电话理解Ajax编写步骤
| 打电话 | ajax请求 | 
| 1.打电话 | 1.创建Ajax对象 | 
| 2.拨号 | 2.连接服务器 | 
| 3.建立连接 | 3.发送请求 | 
| 4.听 | 4.接受返回 | 
1、创建Ajax对象
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | function createXmlHttp() { if (window.XmlHttpRequest) {
 xmlhttp = newXmlHttpRequest();
 }
 if (window.ActiveXObject) {
 try {
 xmlhttp = newActiveXObject("Microsoft.XMLHTTP");
 } catch (e) {
 try {
 xmlhttp = newActiveXObject("msxml2.XMLHTTP");
 } catch (ex) {}
 }
 }
 }
 
 | 
2、连接服务器
| 12
 3
 
 | 
 request.open("GET","get.json",true);
 
 | 
注意
 千万不要把第三个参数指定为false,否则浏览器将停止响应,直到AJAX请求完成。如果这个请求耗时10秒,那么10秒内你会发现浏览器处于“假死”状态。
最后调用send()方法才真正发送请求。GET请求不需要参数,POST请求需要把body部分以字符串或者FormData对象传进去。
3、发送请求
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 
 | 在使用GET方式请求时无需填写参数
 在使用POST方式时参数代表着向服务器发送的数据
 **/
 
 
 createXmlHttp();
 if (!xmlhttp) {
 alert("创建xmlhttp对象异常!");
 return false;
 }
 xmlhttp.open("GET",url,true);
 xmlhttp.onreadystatechange = function() {
 if (xmlhttp.readyState == 4) {
 document.getElementById("xxx").innerHTML = "数据正在加载...";
 if (xmlhttp.status == 200) {
 document.write(xmlhttp.responseText);
 }
 }
 }
 xmlhttp.send();
 
 
 createXmlHttp();
 if (!xmlhttp) {
 alert("创建xmlhttp对象异常!");
 return false;
 }
 xmlhttp.open("POST", url, true);
 xmlhttp.onreadystatechange = function() {
 if (xmlhttp.readyState == 4) {
 document.getElementById("xxx").innerHTML = "数据正在加载...";
 if (xmlhttp.status == 200) {
 document.write(xmlhttp.responseText);
 }
 }
 }
 xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
 xmlhttp.send("name=张三&sex=男");
 
 | 
4、接受返回(XMLHttpRequset取得响应)
| 属性 | 值 | 
| responseText | 获得字符串形式的响应数据 | 
| responseXML | 获得XML形式的响应数据 | 
| status和statusText | 以数字和文本方式返回HTTP状态码 | 
| getAllResponseHeader() | 获取所有的响应报头 | 
| getResponseheader() | 查询响应中的某个字段的值 | 
通过监听onreadystatechange事件,来判断请求的状态(readyState属性:响应返回所处状态).
| 状态码 | 状态 | 所处位置 | 
| 0 | 未初始化 | 还没有调用open()方法 | 
| 1 | 载入 | 已调用send()方法,正在发送请求 | 
| 2 | 载入完成 | send()方法完成,已经收到全部响应内容 | 
| 3 | 解析 | 正在解析响应内容 | 
| 4 | 完成 | 响应内容解析完成,可以在客户端调用了 | 
使用函数简单的封装一个get请求
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 
 | * 一个简单的异步get请求
 * @param {String}   url     请求地址,文件名
 * @param {Function} fnSucc  请求成功时执行的函数,形参为为获取的字符串值.
 * @param {Function} fnFaild 请求失败执行的函数,可选参数
 */
 function get(url, fnSucc, fnFaild) {
 
 var oAjax = null
 
 if (window.XMLHttpRequest) {
 oAjax = new XMLHttpRequest();
 } else {
 
 oAjax = new ActiveXObject("Microsoft.XMLHTTP");
 }
 
 
 oAjax.open("GET", url, true);
 
 oAjax.send();
 
 
 oAjax.onreadystatechange = function () {
 if (oAjax.readyState === 4) {
 if (oAjax.status === 200) {
 fnSucc(oAjax.responseText);
 } else {
 if (fnFaild) {
 fnFaild();
 }
 }
 }
 };
 
 | 
使用Ajax
基础:请求并显示静态TXT文件
- 字符集编码:不一致时会出现乱码
- 缓存,阻止缓存,(使用时间对象添加)
动态数据:请求JS(或JSON)文件
- 并不推荐使用eval,并不推荐使用eval,并不推荐使用eval。因为eval解析数据时会有一系列问题出现。这里是因为只是学习就随意点了。
- 在需要解析请求数据时,推荐使用JSON的方法JSON.parse()可以将一个 JSON 字符串解析成为一个 JavaScript 值。参考 MDN-JSON
安全限制
上面代码的URL使用的是相对路径。如果不是相对路径的话,运行肯定报错。在Chrome的控制台里,还可以看到错误信息。
这是因为浏览器的同源策略导致的。默认情况下,JavaScript在发送AJAX请求时,URL的域名必须和当前页面完全一致。完全一致的意思是,域名要相同(www.example.com和example.com不同),协议要相同(http和https不同),端口号要相同(默认是:80端口,它和:8080就不同)。有的浏览器口子松一点,允许端口不同,大多数浏览器都会严格遵守这个限制。
那是不是用JavaScript无法请求外域(就是其他网站)的URL了呢?方法还是有的,大概有这么几种:
代理服务器再把结果返回,这样就遵守了浏览器的同源策略。这种方式麻烦之处在于需要服务器端额外做开发。
- 第三种方式称为JSONP,它有个限制,只能用GET请求,并且要求返回JavaScript。这种方式跨域实际上是利用了浏览器允许跨域引用JavaScript资源
Ajax函数的封装
众所周知,封装的目的是为了更好的重构,便于后期维护,在大项目中更能体现封装的好处,Ajax在网页中又是经常使用到的,所以我们来学习下怎么对Ajax函数进行封装,用前面get请求的例子进行演示
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 
 | * AJAX函数封装
 * @param {string} url     请求地址(必须)
 * @param {object} options 发送请求的选项参数
 * @config {string} [options.type] 请求发送的类型。默认为GET。
 * @config {Object} [options.data] 需要发送的数据。
 * @config {Function} [options.onsuccess] 请求成功时触发,function(oAjax.responseText, oAjax)。(必须)
 * @config {Function} [options.onfail] 请求失败时触发,function(oAjax)。(oAJax为XMLHttpRequest对象)
 * @returns {XMLHttpRequest} 发送请求的XMLHttpRequest对象
 */
 function AJAX(url, options) {
 
 var oAjax = null;
 
 * 此处必须需要使用window.的方式,表示为window对象的一个属性.不存在时值为undefined,进入else
 * 若直接使用XMLHttpRequest,在不支持的情况下会报错
 **/
 if (window.XMLHttpRequest) {
 
 oAjax = new XMLHttpRequest();
 } else {
 oAjax = new ActiveXObject("Microsoft.XMLHTTP");
 }
 
 
 
 var param = "";
 
 var data = options.data ? options.data : -1;
 if (typeof (data) === "object") {
 for (var key in data) {
 if (data.hasOwnProperty(key)) {
 param += key + "=" + data[key] + "&";
 }
 }
 param.replace(/&$/, "");
 } else {
 param = "timestamp=" + new Date().getTime();
 }
 
 
 var type = options.type ? options.type.toUpperCase() : "GET";
 if (type === "GET") {
 oAjax.open("GET", url + "?" + param, true);
 oAjax.send();
 } else {
 oAjax.open("POST", url, true);
 oAjax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
 oAjax.send(param);
 }
 
 
 
 oAjax.onreadystatechange = function () {
 if (oAjax.readyState === 4) {
 if (oAjax.status === 200) {
 
 options.onsuccess(oAjax.responseText, oAjax);
 } else {
 
 
 if (options.onfail) {
 options.onfail(oAjax);
 }
 }
 }
 };
 return oAjax;
 }
 
 | 
另外一个Ajax封装实例
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 
 | *author: Ivan
 *date: 2014.06.01
 *参数说明:
 *opts: {'可选参数'}
 **method: 请求方式:GET/POST,默认值:'GET';
 **url:    发送请求的地址, 默认值: 当前页地址;
 **data: string,json;
 **async: 是否异步:true/false,默认值:true;
 **cache: 是否缓存:true/false,默认值:true;
 **contentType: HTTP头信息,默认值:'application/x-www-form-urlencoded';
 **success: 请求成功后的回调函数;
 **error: 请求失败后的回调函数;
 */
 function ajax(opts){
 
 var defaults = {
 method: 'GET',
 url: '',
 data: '',
 async: true,
 cache: true,
 contentType: 'application/x-www-form-urlencoded',
 success: function (){},
 error: function (){}
 };
 
 
 for(var key in opts){
 defaults[key] = opts[key];
 }
 
 
 if(typeof defaults.data === 'object'){
 var str = '';
 for(var key in defaults.data){
 str += key + '=' + defaults.data[key] + '&';
 }
 defaults.data = str.substring(0, str.length - 1);
 }
 
 defaults.method = defaults.method.toUpperCase();
 
 defaults.cache = defaults.cache ? '' : '&' + new Date().getTime() ;
 
 if(defaults.method === 'GET' && (defaults.data || defaults.cache))    defaults.url += '?' + defaults.data + defaults.cache;
 
 
 
 var oXhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
 
 oXhr.open(defaults.method, defaults.url, defaults.async);
 
 if(defaults.method === 'GET')
 oXhr.send(null);
 else{
 oXhr.setRequestHeader("Content-type", defaults.contentType);
 oXhr.send(defaults.data);
 }
 
 oXhr.onreadystatechange = function (){
 if(oXhr.readyState === 4){
 if(oXhr.status === 200)
 defaults.success.call(oXhr, oXhr.responseText);
 else{
 defaults.error();
 }
 }
 };
 }
 
 | 
调用方式:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | var ajax1 = ajax({url: '1.php',
 ata: {name: 'test', sex: 'male', age: '23'},
 success: function (data){ alert('返回数据是:' + data); }
 });
 
 var ajax2 = ajax({
 url: '2.php',
 data: 'name=test&sex=male&age=23',
 cache: false,
 success: function (data){ alert('返回数据是:' + data); },
 error: function (){ alert('请求失败...')}
 });
 
 `
 
 |