Ajax 与服务器异步交互的核心便是XMLHttpRequest ,有了XMLHttpRequest 才使得Ajax与后台有了交互能力。
1.首先介绍XMLHttpRequest对象的方法:
(1)abort---------------------------------停止发送当前请求
(2)getAllResponseHeaders---------------获得服务器返回的所有响应头
(3)getResponseHeader(“headerLabel”)—根据响应头的名字来获取相应的响应头
(4)open(“method”, “URL”[,asyncFlag[,“userName”,[,“password”]]])
------------------建立与服务器的URL的连接,并设置请求的的方法,以及是否使用异步请求,如果远程服务需要用户名和密码,则提供相应的用户名和密码
(5)send(content)------------------------发送请求,其中content是请求的参数,如果不需要传递参数就将其设为null,在get方式提交时参数拼接在URL后面的,因此就将content设为null,不过以post方式提交也可以将参数拼接在URL后面的,此时也将content设为null,但也可以将参数放到content中进行传递。
(6)setRequestHeader(“label”,“value”)----该方法一般是在post方式提交的时候用到的,post提交请求前需要先设置请求头。
2.无论是何种请求,使用XMLHttpRequest进行连接都应该按照如下步骤:
(1)初始化XMLHttpRequest对象,需要根据不同的浏览器进行不同的创建,因此首先需要判断浏览器的类别
(2)打开与服务器的连接(使用open(“method”, “URL”[,asyncFlag[,“userName”,[,“password”]]]))。打开连接时,指定发送请求的方法:采用get或post;指定是否以异步方式(true为采用异步)
(3)设定监听XMLHttpRequest状态改变的事件处理函数(即设定的回调函数)
(4)发送请求(使用send(content))
3.XMLHttpRequest对象常用的属性:
(1)onreadystatechange-------------------用于指定XMLHttpRequest对象状态改变时的事件处理函数。onreadystatechange属性的作用与按钮对象的onclick属性一样,
它们都是事件处理属性。即XMLHttpRequest是事件源,它可以引发readystatechange事件,当程序将一个函数引用赋给XMLHttpRequest对象的readystatechange属性,
如:objXMLHttp.onreadystatechange = processResponse;processResponse函数即成为XMLHttpRequest对象的事件处理器,每次XMLHttpRequest对象的状态
改变都会触发监听该事件的事件处理器,因此我们需要在事件处理器即函数中进行正当的判断来实现,具体的操作见代码
XMLHttpRequest对象的几种状态:
—> 0 ---------------------XMLHttpRequest对象还没有完成初始化
—> 1 ---------------------XMLHttpRequest对象开始发送请求
—> 2 ---------------------XMLHttpRequest对象的请求发送完成
—> 3 ---------------------XMLHttpRequest对象开始读取服务器的响应
—> 4 ---------------------XMLHttpRequest对象读取服务器响应结束
以上的状态就是通过下面的readyState属性来进行读取的
(2)readyState----------------------------XMLHttpRequest对象的处理状态
(3)responseText-------------------------用于获取服务器的响应文本
(4)responseXML-------------------------用于获取服务器端响应的XML文档对象
(5)status--------------------------------该属性是服务器返回的状态文本信息,只有当服务器的响应已经完成(即readyState==4),才会有这个状态码
服务器常用的状态码和对应的含义如下:
—> 200 -------------------服务器响应正常
—> 304 -------------------该资源在上次请求之后没有任何修改,这个通常用于浏览器的缓存机制,我们为了在请求时放在读取缓存一般会在url地址上拼接上一个时间戳来骗过浏览器
—> 400 -------------------无法找到请求的资源
—> 401 -------------------访问资源的权限不足
—> 403 -------------------没有权限访问资源
—> 404 -------------------需要访问的资源不存在
—> 405 -------------------需要访问的资源被禁止
—> 407 -------------------访问的资源需要代理身份验证
—> 414 -------------------请求的url太长
—> 500 -------------------服务器内部错误
(6)statusText----------------------------该属性是服务器返回的状态文本信息(与status对应),只有当服务器的响应已经完成,才会有这个状态文本信息
下面演示完整的ajax交互
页面:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<script type="text/javascript" src = "js/XMLHttpRequestTest.js"></script>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>AjaxTest.html</title>
<body>
<input type = "text" name = "content" id = "content" >
<input type = "button" name = "get" value = "GET发送" onclick = "getSend()">
<input type = "button" name = "post" value = "POST发送" onclick = "postSend()">
</body>
</html>
AJAX
var objXMLHttp;
/**
* 进行createXMLHttpRequest对象的创建,由于不同的浏览器厂商对于XMLHttpRequest的支持不一样,因此创建的时候需要根据不同的浏览器进行创建
* */
function createXMLHttpRequest(){
//对于Firefox,Opera等遵守DOM 2规范的浏览器
if(window.XMLHttpRequest){
objXMLHttp = new XMLHttpRequest();
}
//对于iE浏览器
else{
//将IE浏览器不同的XMLHttp实现声明为数组
var MSXML = ['MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'];
//依次对每个XMLHttp创建XMLHttpRequest对象
for(var i = 0; n< MSXML.length; i++){
try{
//微软发布的是ActiveX控件
objXMLHttp = new ActiveXObject(MSXML[i]);
//如果正常创建XMLHttpRequest对象就使用break跳出循环
break;
}catch(e){
alert("创建XMLHttpRequest对象失败");
}
}
}
}
/**
* 通过post方式提交
* */
function postSend(){
var value = document.getElementById("content").value;
alert(value);
//初始化XMLHttpRequest();
createXMLHttpRequest();
//创建请求的URL
var url = "ajaxServlet"
//打开与服务器的链接,使用post方式
objXMLHttp.open("post",url,true);
//post 方式需要设置请求消息头
objXMLHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
//设置处理响应的回调函数
objXMLHttp.onreadystatechange = processResponse;
//发送请求并设置参数,参数的设置为param=value的形式
objXMLHttp.send("value="+value);
}
/**
* 通过GET请求
* */
function getSend(){
var value = document.getElementById("content").value;
//alert(value);
//初始化XMLHttpRequest对象
createXMLHttpRequest();
alert("创建成功");
//创建请求的URL,get方式采用url拼接参数
var url = "ajaxServlet?value="+value;
objXMLHttp.open("GET", url, true);
//设置处理响应的回调函数
objXMLHttp.onreadystatechange = processResponse;
objXMLHttp.send(null);
}
/**
* 设定的回调函数
* */
function processResponse(){
//响应完成且响应正常
if(objXMLHttp.readyState == 1){
alert("XMLHttpRequest对象开始发送请求");
}else if(objXMLHttp.readyState == 2){
alert("XMLHttpRequest对象的请求发送完成");
}else if(objXMLHttp.readyState == 3){
alert("XMLHttpRequest对象开始读取服务器的响应");
}else if(objXMLHttp.readyState == 4){
alert("XMLHttpRequest对象读取服务器响应结束");
if(objXMLHttp.status == 200){
//信息已经成功返回,开始处理信息
//先捕获下所有的请求头
var headers = objXMLHttp.getAllResponseHeaders();
alert("所有的请求头= "+headers);
//得到服务器返回的信息
var infor = objXMLHttp.responseText;
alert("服务器端的响应 = "+infor);
}else{
alert("所请求的服务器端出了问题");
}
}
}
服务器端:
package xidian.sl.ajax;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AjaxServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
String value = request.getParameter("value");
System.out.println("value"+ value);
out.print("得到的value为 = "+ value);
}
}
发现上面使用get方式进行提交时,如果输入中文传到服务器端就出现乱码:
输入:
然后点击GET发送,然后查看服务器端打印到控制台的value:
原因:当使用GET方式发送请求时,请求的参数是拼接在url地址后面的,而根据http的传输方式,如果传输的参数为中文,就会编码成url的格式进行传递,此时我们就要对其做点处理了:
(1).在服务器端进行编码格式的转变:先将参数按ISO-8859-1字符集编码成字节数组,然后按UTF-8字符集将该字节数组解码为字符串:
String param = new String(请求参数.getBytes(“ISO-8859-1”), “UTF-8”),但这种方式并不是全能的,因为我们这里是将所有的参数都以UTF-8进行解码,但不同的浏览器请求参数的编码格式是不一样的,不一定为UTF-8,如IE默认的编码格式为GBK,需要改成new String(请求参数.getBytes(“ISO-8859-1”), “GBK”),因此我们一般选择第二种方式或第三种方式
(2).页面端发出的数据做一次encodeURI,服务器端使用 new String(请求参数.getBytes(“iso8859-1”),“utf-8”)如:
var url= “AJAXServer?name=”+encodeURI($("#userName").val() ) ;
(3)页面端发出的数据做两次encodeURI处理, 服务器端用URLDecoder.decode(请求参数,“utf-8”);具体见:http://www.cnblogs.com/shenliang123/archive/2012/04/19/2456758.html
在POST请求时Ajax应用默认采用UTF-8字符集来编码请求参数,在服务器端可以不使用request.setCharacterEncoding(“UTF-8”);
但养成良好的习惯还是建议写request.setCharacterEncoding(“UTF-8”);
还有一个问题就是为了不让浏览器读取缓存,我们需要在url地址后拼接一个时间戳来骗过浏览器:
//给URL增加时间戳,骗过浏览器,不读取缓存
function convertURL(url){
//获取时间戳
var timstamp=(new Date()).valueOf();
//将时间戳信息拼接到URL上
if(url.indexOf("?")>=0){//用indexof判断该URL地址是否有问号
url=url+"&t="+timstamp;
}else{
url=url+"?t="+timstamp;
}
return url;
}
详细见:http://www.cnblogs.com/shenliang123/archive/2012/04/19/2456758.html
从返回的结果可以看出:返回的所有响应头并不是组成一个数组,而是由“名:值”组成的键值对字符串
到此我们对于XMLHttpRequest了解的差不多了,但我们上面介绍的都是文本的请求,在回调函数中是通过responseText属性来获取服务器端返回的文本,下面我们要介绍发送
xml请求,这个适合于发送复杂的参数到服务器端,我们可以将客户端页面的参数封装为xml字符串形式:
在上面的js中添加两个方法:
/**
* 创建xml文档
* */
function createXML(){
//开始创建XML文档,countrys是根元素
var xml = "<countrys>"
//获取country元素,并获取其所有的子元素
var options = document.getElementById("country").childNodes;
var option = null;
//遍历城市下拉列表的所有选项
for(var i = 0; i< options.length; i++){
option = options[i];
//判断是否被选中
if(option.selected){
//在countrys节点下增加一个country子节点,这里需要对 / 进行转义
xml = xml+"<country>"+option.value+"<\/country>";
}
}
//结束xml根节点
xml = xml+"<\/countrys>";
//返回
return xml;
}
/**
* 使用xml进行传递
*
*/
function send(){
//初始化XMLHttpRequest对象
createXMLHttpRequest();
//创建请求的URL
var url = "xmlServlet"
//打开与服务器的连接,使用post方式
objXMLHttp.open("POST", url, true);
//post方式需要设置请求消息头
objXMLHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
//设置处理响应的回调函数
objXMLHttp.onreadystatechange = processResponseXML;
//发送xml请求,此时参数的设置不再是param=value的形式进行发送,而是直接采用xml字符串作为参数
objXMLHttp.send(createXML());
}
/**
* xml请求的回调函数
* */
function processResponseXML(){
//响应完成且响应正常
if(objXMLHttp.readyState == 1){
alert("XMLHttpRequest对象开始发送请求");
}else if(objXMLHttp.readyState == 2){
alert("XMLHttpRequest对象的请求发送完成");
}else if(objXMLHttp.readyState == 3){
alert("XMLHttpRequest对象开始读取服务器的响应");
}else if(objXMLHttp.readyState == 4){
alert("XMLHttpRequest对象读取服务器响应结束");
if(objXMLHttp.status == 200){
//信息已经成功返回,开始处理信息
//先捕获下所有的请求头
var headers = objXMLHttp.getAllResponseHeaders();
alert("所有的请求头= "+headers);
//得到服务器XML相应,这里是通过responseXML属性来获得,这也是唯一区别的地方
var infor = objXMLHttp.responseXML;
alert("服务器端的响应 = "+infor);
}else{
alert("所请求的服务器端出了问题");
}
}
}
页面端:就是一个可以多选的下拉框
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>XMLAjaxTestl.html</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script type="text/javascript" src = "js/XMLHttpRequestTest.js"></script>
</head>
<body>
<!-- 添加 multiple = "multiple"属性后下拉框可以为多选-->
<select name = "country" id = "country" multiple = "multiple">
<option value = "1" selected = selected>浙江</option>
<option value = "2">北京</option>
<option value = "3">上海</option>
</select>
<input type = "button" name = "send" value = "发送" onclick = "send()"/>
</body>
</html>
服务器端的处理:
package xidian.sl.ajax;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.XPPReader;
public class XMLServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
StringBuffer buffer = new StringBuffer();
String line = null;
//通过request获取输入流
BufferedReader reader = request.getReader();
//依次读取请求输入流中的数据
while((line = reader.readLine())!=null){
buffer.append(line);
}
//将从输入流中读取到的数据转化为字符串
String xml = buffer.toString();
InputStream is = new ByteArrayInputStream(xml.getBytes());
//采用dom4j解析xml字符串.read(new ByteArrayInputStream(xml.getBytes()));
Document xmldoc = new XPPReader().read(is);
//获取countrys节点的所有字节点
List countryList = xmldoc.getRootElement().elements();
//定义服务器的响应结果
String result = "";
for(Iterator iterator = countryList.iterator();iterator.hasNext();){
org.dom4j.Element country = (Element)iterator.next();
if(country.getText().equals("1")){
result += "杭州";
}else if(country.getText().equals("2")){
result += "海淀";
}else if(country.getText().equals("3")){
result += "明珠";
}
}
out.print(result);
}
}
由于发送到服务器端的是一个xml字符串,因此服务器端不能直接通过request.getParameter();来得到请求参数,而是必须以流的形式来获取请求参数;
下面将给出一个通用的并且是使用池的技术管理的XMLHttpRequest,因为对于大型的js应用,XMLHttpRequest的使用时很频繁的,因此使用缓存会更加的高效:
var XMLHttp = {
//定义第一个属性,该属性用于缓存XMLHttpRequest
XMLHttpRequestPool:[],
//对象的第一个方法用于返回一个XMLHttpRequest对象
getInstance:function(){
//从XMLHttpRequest对象池中取出一个空闲的XMLHttpRequest对象
for(var i = 0; i< XMLHttpRequestPool.length; i++){
//判断XMLHttpRequest对象是否为空闲,只需要判断readyState就可以了,如果readyState为0或4就表示当前XMLHttpRequest对象为空闲
if(this.XMLHttpRequestPool[i].readyState == 0|| this.XMLHttpRequestPool[i].readyState == 4){
return this.XMLHttpRequestPool[i];
}
}
//如果没有空闲的就只能再次创建一个新的XMLHttpRequest对象
this.XMLHttpRequestPool[XMLHttpRequestPool.length] = this.createXMLHttpRequest();
//返回刚刚创建的XMLHttpRequest对象
return this.XMLHttpRequestPool[XMLHttpRequestPool.length-1];
},
//创建新的XMLHttpRequest对象
createXMLHttpRequest:function(){
//对于Firefox,Opera等遵守DOM 2规范的浏览器
if(window.XMLHttpRequest){
var objXMLHttp = new XMLHttpRequest();
}
//对于IE浏览器
else{
//将IE浏览器不同的XMLHttp实现声明为数组
var MSXML = ['MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'];
//依次对每个XMLHttp创建XMLHttpRequest对象
for(var i = 0; n< MSXML.length; i++){
try{
//微软发布的是ActiveX控件
var objXMLHttp = new ActiveXObject(MSXML[i]);
//如果正常创建XMLHttpRequest对象就使用break跳出循环
break;
}catch(e){
alert("创建XMLHttpRequest对象失败");
}
}
}
//Mozilla的某些版本没有readyState属性
if(objXMLHttp.readyState == null){
//直接设置为0
objXMLHttp.readyState = 0;
//对于那些没有readyState属性的浏览器,将load动作与与下面函数相关联
objXMLHttp.addEventListener("load", function(){
//当从服务器上加载完数据后,将readyState属性设为4
objXMLHttp.readyState = 4;
if(typeof objXMLHttp.onreadystatechange == "function"){
objXMLHttp.onreadystatechange();
}
},false);
}
return objXMLHttp;
},
//定义对象的第三个方法:发送请求(方法[post:get],地址,数据源,回调函数)
sendRequest:function(method, url, data, callback){
//得到XMLHttpRequest对象
var objXMLHttp = this.getInstance();
with(objXMLHttp){
try{
//增加一个额外的请求参数,用于防止IE读取服务器缓存
uri = convertURL(url);
//打开与服务器的连接
open(method, uri, true);
//对于使用post提交的
if(method == "POST"){
//设定消息请求头
setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
send(data);
}
//对于用get方式提交的
if(method == "GET"){
send(null);
}
//设置状态改变的回调函数
onreadystatechange = function(){
//当服务器响应结束并得到了正常的服务器响应
if(objXMLHttp.readyState == 4&& objXMLHttp.status == 200){
//调用回调函数
callback(objXMLHttp);
}
}
}catch(e){
alert(e)
}
}
},
convertURL:function (url){
//获取时间戳
var timstamp=(new Date()).valueOf();
//将时间戳信息拼接到URL上
if(url.indexOf("?")>=0){//用indexof判断该URL地址是否有问号
url=url+"&t="+timstamp;
}else{
url=url+"?t="+timstamp;
}
return url;
}
}
上面的池的实现就是简单的使用一个数组来存储已存在的XMLHttpRequest对象,这样这个数组就成了一个XMLHttpRequest对象池,实现缓存的作用,每次发送请求只要从对象池中取出一个闲置的XMLHttpRequest对象,如果此时不存在闲置的对象就创建一个新的XMLHttpRequest对象
以后我们在使用Ajax的时候只需要将这个js代码进行引入,然后直接调用方法XMLHttp.sendRequest(“POST/GET”, url, data, callback);
这样是不是有点像jquery对于get方式提交的封装:$.get(“AjaxServer?name=”+userName,null,callback);
具体实例可以见:http://www.cnblogs.com/shenliang123/archive/2012/04/19/2456735.html
引用:http://www.cnblogs.com/shenliang123/archive/2012/05/13/2498524.html