AJAX
A.原生AJAX
1.概述
AJAX:Asynchronous JavaScript and XML,异步的JavaScript和XML
不是新的编程语言,而是一种使用现有标准的新方法
2.异步概念
客户端和服务端不必相互等待,而是进行一种并发的操作
用户在发送请求后继续当前工作:浏览或提交信息
在服务器响应完成后,AJAX引擎会将跟新的数据现实给用户
3.AJAX和传统应用区别(异步和同步区别)
AJAX使用的是异步,传统的Web使用的是同步
a.同步更新是需要对整个页面进行更新,并且以新页面的形式显示出来
b.异步更新是后台和服务器进行少量数据交换,即不重新加载整个网页就可以对网页的某部分进行更新,AJAX减少了用户的等待时间
4.优点
a.通过异步模式,网页无刷新,提升了用户体验
b.优化了浏览器和服务器之间的传输,减少不必要的数据往返,减少了带宽占用
c.AJAX引擎在客户端运行,承担了一部分本来由服务器承担的工作,从而减少了大用户量下的服务器负载
d.基于标准化的并被广泛支持的技术,不需要下载插件或者小程序
5.缺点
a.不支持浏览器的back按钮
b.安全问题:暴露了与服务器交互的细节
c.搜索引擎的支持比较弱
d.破坏了程序的异常机制
e.不容易调试
6.应用场景
a.请求的提交是为了页面数据显示,用户不希望看到网页的全部刷新
b.如果请求提交后,用户能从页面感觉到提交结果,最好使用AJAX技术
c.若请求提交后,用户不能从页面感觉到提交动作
d.复杂的UI,C/S模式
7.技术组成
a.HTML:用于建立Web表单并确定应用程序其他部分使用的字段
b.JS:实现AJAX应用程序的编程语言,帮助改进与服务器应用程序的通信
c.XMLHttpRequest对象:浏览器内置的数据异步发送和接收对象,是AJAX核心
是AJAX的基础,所有(IE5和IE6使用ActiveXObject)现代浏览器均支持
用于在后台与服务器交换数据,可以在不重新家在整个网页的情况下
对网页的某部分进行更新
d.文档对象模型DOM:用于处理HTML结构和服务器返回的XML
e.XML:数据传输格式,经常使用XML和JSON进行数据的交换
8.步骤
a.创建XMLHttpRequest对象
b.使用open()方法和服务器建立联系,传递方法类型,url地址,提交方式
GET:快
POST:
1)无法使用缓存文件(更新服务器上的文件或数据库)
2)向服务器发送大量数据(POST没有数据量限制)
3)发送包含未知字符的用户输入时,POST更稳定可靠
c.使用onreadystatechange属性设置回调函数,需要判断request和response状态码
接受服务端信息的触发函数,服务器会通知当前的通信状态
通过改变对象的readyState状态实现,每次改变都会触发该函数
d.使用send()方法发送请求
模拟一个注册用户名验证
1)前端代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>AJAX</title> </head> <body> <form action="#"> <input type="text" name="uname" id="uname" /><span id="tip"></span><br> <input type="button" id="btn" value="提交" /> </form> </body> <script type="text/javascript"> // 1)创建XMLHttpRequest对象 function createXHR() { // 定义对象 var xhr; // 跨浏览器支持判断 if (window.XMLHttpRequest) { // 大多现代浏览器都内建对象 xhr = new XMLHttpRequest(); } else { // 老版本的(IE5和IE6) xhr = new ActiveXObject("Microsoft.XMLHTTP"); } // 返回 return xhr; } // 向服务器发送请求 function sendRequest() { // 获取表单信息 var name = document.getElementById("uname").value; // 调用创建对象 var xhr = createXHR(); // 和服务端进行关联:请求方式,文件服务器虚拟路径,异步(true)或同步(false) xhr.open("GET", "RegisterServlet?name=" + name, true); // 回调函数 // 在发送前,需要定义接受服务端信息后的触发函数 xhr.onreadystatechange = function() { process(xhr); } // 发送参数 // GET不需要发送,直接为空 xhr.send(null); } // 回调函数 function process(xhr) { // 当readyState为4,并且status为200 if(xhr.readyState == 4 && xhr.status == 200){ // 获取响应信息 var msg = xhr.responseText; // 判断 if(msg == "yes") { document.getElementById("tip").innerHTML = "<font color='green'>用户名可用</font>"; } else if(msg == "no") { document.getElementById("tip").innerHTML = "<font color='red'>用户名已存在</font>"; } } } // 当点击按钮,触发发送异步请求 document.getElementById("btn").onclick = sendRequest; </script> </html>
2)后台
3)运行服务器,测试package org.xxxx.demo01; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/RegisterServlet") public class RegisterServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取参数 String name = request.getParameter("name"); // 非空 name = (name != null) ? name : ""; // 获取输出流 PrintWriter writer = response.getWriter(); // 判断 if (name.equals("zhangsan")) { writer.write("no"); } else { writer.write("yes"); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
a)情况1
b)情况2
9.responseText
是XMLHttpRequest对象的一个属性,封装了服务端返回的字符串形式数据
a.普通字符串,客户端直接当作普通文本处理
b.JSON格式:使用{}包含的文本
文件类型:.json
文本MIME类型:application/json
10.JSON中数据的赋值和获取
因为JSON使用JS语法,所以无需额外的软件就能处理JS中的JSON
<script type="text/javascript"> function() { var employees = [ {"firstName" : "Bill", "lastName" : "Gates"}, {"firstName" : "George", "lastName" : "Bush"} ]; // 给第一组赋值 employees[0].lastName = "Jobs"; // 取值 employees[0].lastName; } </script>
11.服务端JSON数据的使用
接收的服务器数据是JSON字符串,可以使用JSON.parse()方法将数据转换为JS对象
服务端必须确保json格式正确性:"{\"name\" :\" "+ name"\", \"pass\" : 123456}";
客户端获取:var str = JSON.parse(xmlHttp.responseText);
需求:获取用户名,响应用户名和密码的JSON格式字符串
a.前端
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <form action="#"> <input type="text" name="uname" id="uname"><span id="tip"></span><br /> <input type="button" id="btn" value="提交"> </form> </body> <script type="text/javascript"> // 创建XMLHttpRequest对象 function createXHR(){ var xhr; if (window.XMLHttpRequest) { xhr = new XMLHttpRequest(); } else { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } return xhr; } // 发送请求 function sendRequest(){ var name = document.getElementById("uname").value; var xhr = createXHR(); // 和服务端关联 xhr.open("POST", "JSONServlet", true); // 回调 xhr.onreadystatechange = function() { process(xhr); } // POST请求必须添加以下代码 xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); // 发送参数:POST方式参数键值对必须写在send xhr.send("name=" + name); } // 回调函数 function process(xhr) { if(xhr.readyState==4&&xhr.status==200) { // 转换json字符串为一个js对象 var user = JSON.parse(xhr.responseText); document.getElementById("tip").innerHTML = user.name + "==" + user.pass; } } document.getElementById("btn").onclick = sendRequest; </script> </html>
b.后台
package org.xxxx.demo01; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/JSONServlet") public class JSONServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置响应为JSON response.setContentType("application/json;charset=utf-8"); // 获取参数 String name = request.getParameter("name"); // 非空判断 if (name != null) { // 响应 {"name":"name","pass":"123456"} response.getWriter().write("{\"name\":\"" + name + "\",\"pass\":\"123456\"}"); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
3)结果
12.解析XML内容
服务端返回xml数据时,必须设置
response.setContentType("text/xml;charset=utf-8");
1)前端
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <form action="#"> <input type="text" name="uname" id="uname"><span id="tip"></span><br /> <input type="button" id="btn" value="提交"> </form> </body> <script type="text/javascript"> // 创建对象 function createXHR() { var xhr; if (window.XMLHttpRequest) { xhr = new XMLHttpRequest(); } else { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } return xhr; } // 发送请求 function sendRequest() { var name = document.getElementById("uname").value; var xhr = createXHR(); // 关联服务器 xhr.open("POST", "XMLServlet", true); // 回调 xhr.onreadystatechange = function() { process(xhr); } // 设置响应头 xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); // 发送 xhr.send("name=" + name); } // 回调函数 function process(xhr) { if(xhr.readyState==4&&xhr.status==200){ //返回responseXML的dom对象 var name = xhr.responseXML.getElementsByTagName('name')[0].firstChild.nodeValue; var pass = xhr.responseXML.getElementsByTagName('pass')[0].firstChild.nodeValue; document.getElementById('tip').innerHTML = name + "==" + pass; } } document.getElementById('btn').onclick = sendRequest; </script> </html>
2)后台
package org.xxxx.demo01; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/XMLServlet") public class XMLServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置响应头 response.setContentType("text/xml;charset=utf-8"); // 响应 response.getWriter().write("<user><name>张三</name><pass>123456</pass></user>"); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
3)结果
13.参数传递
a.GET:需要再URL后添加参数信息
b.POST:需要再body中传递参数
c.中文乱码问题:tomcat8.5以上不会出现,低版本需要解码
14.练习
省市二级联动
a.前端
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>省市二级联动</title> </head> <body> <form action="#"> <select id="provs"> <option value="1">山西省</option> <option value="2">陕西省</option> <option value="3">湖北省</option> </select> <select id="cities"></select> </form> </body> <script type="text/javascript"> // 创建对象 function createXHR() { var xhr; if (window.XMLHttpRequest) { xhr = new XMLHttpRequest(); } else { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } return xhr; } // 发送请求 function sendRequest() { var pid = document.getElementById("provs").value; var xhr = createXHR(); // 关联服务端 xhr.open("GET", "SelectServlet?pid=" + pid, true); // 回调 xhr.onreadystatechange = function() { process(xhr); } // 发送参数 xhr.send(null); } // 回调 function process(xhr) { if (xhr.readyState == 4 && xhr.status == 200) { // 解析成JSON对象 var jsonObjs = JSON.parse(xhr.responseText); var len = jsonObjs.length; var citis = document.getElementById("cities"); // 下拉框清零 citis.options.length = 0; for(var i = 0; i < len; i++) { var obj = jsonObjs[i]; // 创建option var option = new Option(obj.name, obj.id); citis.appendChild(option); } } } document.getElementById('provs').onchange = sendRequest; </script> </html>
b.后台
package org.xxxx.demo01; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/SelectServlet") public class SelectServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置 response.setContentType("application/json;charset=UTF-8"); // 获取参数 String pid = request.getParameter("pid"); String jsonStr = ""; // 判断 if (pid.equals("1")) { jsonStr = "[{\"id\":1,\"name\":\"太原\"}, {\"id\":2,\"name\":\"运城\"}, {\"id\":3,\"name\":\"临汾\"}]"; } else if (pid.equals("2")) { jsonStr = "[{\"id\":1,\"name\":\"西安\"}, {\"id\":2,\"name\":\"延安\"}, {\"id\":3,\"name\":\"宝鸡\"}]"; } else if (pid.equals("3")) { jsonStr = "[{\"id\":1,\"name\":\"武汉\"}, {\"id\":2,\"name\":\"襄阳\"}, {\"id\":3,\"name\":\"宜昌\"}]"; } // 响应 response.getWriter().write(jsonStr); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
c.结果
B.JQuery下的AJAX
1.概述
JQuery提供了几个用于发送AJAX请求的函数
其中最核心也是最复杂得是JQuery.ajax(options)
所有的其他Ajax函数都是它的一个简化调用
当我们想要完全控制AJAX时可以使用此结果
否则还是使用简化方法如get,post,load等更加方便
2.ajax()方法
一般格式
$.ajax({
type:POST, 可选,默认为GET
url:url, 必选,请求的发送url
data:data, 可选,发送的数据
dataType:dataType 可选,预期返回的数据类型
success:sucHandler 可选,请求成功执行的函数
error:errorHandler 可选,请求失败执行的函数
});
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <script type="text/javascript" src="js/jquery.js"></script> </head> <body> <form action="#"> <input type="text" name="uname" id="uname"><span id="tip"></span><br /> <input type="button" id="btn" value="提交"> </form> </body> <script type="text/javascript"> $(document).ready(function() { $("#btn").on("click", function() { $.ajax({ "url":"RegisterServlet", "data":{"name":$("#uname").val()}, "success":function(data) { document.getElementById("tip").innerHTML = data; }, "error":function(XMLHttpRequest, textStatus, errorThrown) { alert(textStatus); } }); }); }); </script> </html>
3.参数详解
a.data
要求为Object或String类型的参数,发送到服务器的数据
对象必须为key/value格式
b.success
要求为function类型的函数,是请求成功后调用的回调函数
有两个参数function(data, textStatus)
1)有服务器返回,并根据dataType参数进行处理后的数据
2)描述状态的字符串
c.error
要求为function类型的函数,是请求失败后调用的回调幻术
有三个参数function(XMLHttpRequest, textStatus, errorThrown)
通常情况下,textStatis和erroeThrown只有一个包含信息
4.ajax()方法参数传递方式
a.拼接字符串
data:"name=" + val
b.拼接在url后面
url:"loginServlet?name=" + name
c.json
data:{
name:name,
password:pass
}
d.序列化表单内容为字符串
data:$("#form1").serialize();
5.get()方法
get(url, [data], [callback])
通过远程HTTP GET请求再入信息,是一个简单的GET
请求功能以取代复杂$.ajax,请求成功时可调用回调函数
如果需要在出错时执行函数,请使用$.ajax
url(String):逮载入页面的URL地址
data(Map):可选,带发送key=value参数
callback(fucntion):可选,再入成功时回调函数
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <script type="text/javascript" src="js/jquery.js"></script> </head> <body> <form action="#"> <input type="text" name="uname" id="uname"><span id="tip"></span><br /> <input type="button" id="btn" value="提交"> </form> </body> <script type="text/javascript"> $(document).ready(function() { $("#btn").on("click", function() { $.get("RegisterServlet", "name=" + $("#uname").val(), function(data) { document.getElementById("tip").innerHTML = data; }); }); }); </script> </html>
6.post()方法
post(url, [data], [callback])
一个简单的post请求功能以取代复杂$.ajax
用法与get()方式相同
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <script type="text/javascript" src="js/jquery.js"></script> </head> <body> <form action="#"> <input type="text" name="uname" id="uname"><span id="tip"></span><br /> <input type="button" id="btn" value="提交"> </form> </body> <script type="text/javascript"> $(document).ready(function() { $("#btn").on("click", function() { $.post("RegisterServlet", "name=" + $("#uname").val(), function(data) { document.getElementById('tip').innerHTML = data; }); }); }); </script> </html>
C.跨域
1.概述
不同的域之间相互请求资源,就叫跨域(跨服务器)
2.域名地址组成
http://www.baidu.8080/script/jquery.js
http://协议类型
www:子域名
baidu:主域名
script/jquery.js请求的地址
3.跨域的JS支持
当协议、子域名、主域名、端口号中任意一个不想同时,都算不同的域
浏览器安全的基石是“同源政策”,为了保证用户信息的安全,防止网站窃取数据
同源政策规定AJAX请求只能发给同源地址,否则报错
随着会联网的发展,如果非同源,有三种行为受到限制
a.Cookie,LocalStorage和IndexDB无法读取
b.DOM无法获得
c.AJAX请求不能发送
虽然这些限制是必要的,但有时很不方便
4.JSONP
JSON with Padding:是json的一种使用模式
可以让网页从别的域名那获取资料,即跨域读取数据
是一种非正式传输协议,允许用户传递一个callback参数给服务端
然后服务端返回数据时会将这个callback参数作为函数名来包裹JSON数据
这样客户端可以随意指定自己的函数来自动处理返回数据
但是script标签是一个例外
通过script标签访问不同域的资源则不受限制
利用<script>元素的这个开方策略,网页可以得到从高其他来源动态产生的JSON资料
而这种使用模式就是所谓的JSONP
用JSONP抓到的资料并不是JSON,而是任意的JS
用JS解析器执行而不是用JSON解析器解析
5.实现
调用不同域的js
调用不同域的servlet(打开两个tomcat)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <script type="text/javascript" src="js/jquery.js"></script> </head> <body> <form action="#"> <input type="text" name="uname" id="uname"><span id="tip"></span><br /> <input type="button" id="btn" value="提交"> </form> </body> <script type="text/javascript"> $(document).ready(function() { $("#btn").on("click", function() { // jsonp $.ajax({ "type":"GET", "url":"http://loaclhost:8081/my/InfoServlet", //开启另一个端口为8081的tomcat "dataType":"jsonp", "succcess":function(data) { alert("success"); } }); // 简写 $.getJSON("http://localhost:8081/my/InfoServlet?callback=?", function(data) { alert(data); }); }); }); </script> </html>