通过上一篇文章,我们对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对象
1 2 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、连接服务器
1 2 3
|
request.open("GET","get.json",true);
|
注意
千万不要把第三个参数指定为false,否则浏览器将停止响应,直到AJAX请求完成。如果这个请求耗时10秒,那么10秒内你会发现浏览器处于“假死”状态。
最后调用send()方法才真正发送请求。GET请求不需要参数,POST请求需要把body部分以字符串或者FormData对象传进去。
3、发送请求
1 2 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请求
1 2 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请求的例子进行演示
1 2 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封装实例
1 2 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(); } } }; }
|
调用方式:
1 2 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('请求失败...')} });
`
|