AJAX(Asynchronous Javascript And XML)
传统请求缺点
-
传统请求包含什么
-
直接在浏览器地址栏上输入url
-
点击超链接
-
提交form表单
-
使用JS代码发送请求
-
window.open(url)
-
window.location.href = url
-
document.location.href = url
-
...
-
-
-
传统请求存在的问题
-
页面全部刷新导致用户体验差
-
传统请求导致用户的体验不连贯,有空白期
-
AJAX概述
-
AJAX不能称为一种技术,他是多种技术的综合产物
-
AJAX可以让浏览器发送一种特殊的请求,这种请求是异步的
-
异步:两个操作是并发的,互不影响
-
同步:一个操作需要等待另一个操作的执行后某个位置才能开始执行,两个操作是排队进行的
-
-
AJAX代码属于WEB前段JS代码
-
AJAX应用程序可能使用XML来传输数据,但将数据作为纯文本或JSON文本也同样常见
-
AJAX可以更新网页的部分,而不需要重新加载整个页面
-
AJAX可以做到在同一个网页中同时启动多个请求
XMLHttpRequest对象
-
XMLHttpRequest对象是AJAX的核心对象,发送请求以及接收服务器数据的返回
-
XMLHttpRequest对象,现代浏览器都是支持的,内置了该对象
-
创建XMLHttpRequest对象
-
var xhr = new XMLHttpRequest();
-
-
XMLHttpRequest对象的方法
方法 描述 abort() 取消当前请求 getAllResponseHeaders() 返回头部信息 getResponseHeader() 返回特定的头部信息 open(method,url,async,user,psw) 规定请求 method:请求类型GET/POST;url:文件位置;async:true(异步)/false(同步);user:可选的用户名称;psw:可选的密码 send() 将请求发送到服务器,用于GET请求 send(string) 将请求发送到服务器,用于POST请求 setRequestHeader() 向要发送的报头添加标签/值对 -
XMLHttpRequest对象的属性
属性 描述 onreadystatechange 定义当readState属性发生变化时被调用的函数 readState 保存XMLHttpRequest的状态 0:请求末初始化 1:服务器连接已建立 2:请求已收到 3:正在处理请求 4:请求已完成且响应已就绪 responseText 以字符串(普通文本)返回响应数据 responseXML 以XML数据返回响应数据 status 返回请求的状态号 200:"OK" 403:"Forbidden" 404:"Not Found" statusText 返回状态文本(比如"OK" / "Not Found")
AJAX发送GET请求
-
发送AJAX GET请求前端:
<input type="text" id="username"> <input type="text" id="password"> <button id="button">发送AJAX GET请求</button> <div id="display"></div> <script type="text/javascript"> //页面加载完后执行 window.onload = function(){ //给id为button的组件对象绑定onclick事件,再点击时执行 document.getElementById("button").onclick = function(){ //创建AJAX核心对象 var xhr = new XMLHttpRequest() //注册回调函数 xhr.onreadStatechange = function(){ //当响应已就绪时执行 if(this.readState == 4){ //当响应正常时执行 if(this.status == 200){ //将接收到的响应数据以普通文本的形式输出在id为display的组件对象中 document.getElementById("display").innerHTML = this.responseText }else{ //响应失败输出HTTP协议的状态码 alert("this.status") } } } //获取数据 var username = document.getElementById("username").value var password = document.getElementById("password").value //开启通道 xhr.open("GET","/项目名/请求路径?username="+username+"&password="+password,true) //发送请求 xhr.send() } } </script>
-
发送AJAX GET请求后端:
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); String username = request.getParameter("username"); String password = request.getParameter("password"); out.print("<font color='red'>username="+username+",password="+password+"</font>"); }
AJAX的GET请求的缓存问题
-
对于低版本的IE浏览器,AJAX的GET请求可能走缓存,存在缓存问题
-
在HTTP协议中GET请求的规定为:GET请求会被缓存起来
AJAX发送POST请求
-
发送AJAX POST请求前端:
<input type="text" id="username"> <input type="text" id="password"> <button id="button">发送AJAX GET请求</button> <div id="display"></div> <script type="text/javascript"> //页面加载完后执行 window.onload = function(){ //给id为button的组件对象绑定onclick事件,再点击时执行 document.getElementById("button").onclick = function(){ //创建AJAX核心对象 var xhr = new XMLHttpRequest() //注册回调函数 xhr.onreadStatechange = function(){ //当响应已就绪时执行 if(this.readState == 4){ //当响应正常时执行 if(this.status == 200){ //将接收到的响应数据以普通文本的形式输出在id为display的组件对象中 document.getElementById("display").innerHTML = this.responseText }else{ //响应失败输出HTTP协议的状态码 alert("this.status") } } } //开启通道 xhr.open("POST","/项目名/请求路径",true) //获取数据 var username = document.getElementById("username").value var password = document.getElementById("password").value //模拟AJAX提交form表单,设置请求头的内容类型 xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded") //发送请求 xhr.send("username="+username+"&password="+password) //使用send(String str)方法发送数据,格式必须以"name=value&name=value&name=value"为准 } } </script>
-
发送AJAX POST请求后端:
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); String username = request.getParameter("username"); String password = request.getParameter("password"); out.print("<font color='red'>username="+username+",password="+password+"</font>"); }
基于JSON的数据交换
-
在Web前端,将一个json格式的字符串转换成json对象
-
使用eval函数
var jsonStr = "{\"username\" : \"XiangXi\",\"password\" : \"123456\"}" var jsonObj = eval("(" + jsonStr + ")")
-
调用js中的内置对象JSON的一个方法parse
var jsonStr = "{\"username\" : \"XiangXi\",\"password\" : \"123456\"}" var jsonObj = JSON.parse(jsonStr)
-
-
在Web前端,将一个json对象转换成json格式的字符串
var jsonStr = JSON.stringify({a:'Hello',b:'World'});
-
在Java后端,使用JSON类下的toJSONString方法将一个自定义类转换成json字符串格式
User user = new User(1,"XiangXi","帅哥"); String jsonStr = JSON.toJSONString(user);
基于XML的数据交换
-
在Web前端,将一个xml格式的字符串转换成xml对象
var xmlDoc = this.responseXML//接收返回后,自动封装成document对象(文档对象) var users = xmlDoc.getElementsByTagName("user")//获取所有users的元素,返回一个集合 for (var i = 0; i < users.length; i++){ var user = users[i] var elements= user.childNodes//获取单个元素下的所有子元素,返回一个集合 for (var j = 0; j < elements.length ; j++){ var element = elements[j] if (element.nodeName == "id"){ var id = element.textContext } if (element.nodeName == "uname"){ var uname = element.textContext } if (element.nodeName == "age"){ var age = element.textContext } if (element.nodeName == "sex"){ var sex = element.textContext } } }
-
在Java后端,拼接字符串来返回一个xml格式的字符串
StringBuilder xml = new StringBuilder(); xml.append("<users>"); //集合 xml.append("<user>"); //单个元素 xml.append("<id>"+id+"</id>"); //子元素 xml.append("<uname>"+uname+"</uname>"); xml.append("<age>"+age+"</age>"); xml.append("<sex>"+sex+"</sex>"); xml.append("</user>"); xml.append("</users>"); out.print(xml);
-
XML和JSON都是常用的数据交换格式
-
JSON体积小,解析简单
-
XML体积大,解析复杂
-
AJAX乱码问题
-
对于Tomcat10来说,关于字符集,不需要干涉,不存在乱码问题
-
对于Tomcat9来说
-
GET请求,接收正常,响应存在乱码问题,需要设置字符集:response.setContentType("text/html;charset=UTF-8");
-
POST请求,接收存在乱码问题,需要设置字符集:request.setCharacterEncoding("UTF-8");
-
AJAX的异步与同步
-
设置异步/同步方式
var xhr = new XMLHttpRequest() xhr.open("请求方式","URL",true/false)//true为异步,false为同步
-
何时使用同步方式
-
用户注册:多个信息输入框需要发送ajax请求进行校验,注册按钮需在所有信息校验完成后才能发送ajax请求
-
JavaScript语言中定义类
function User(usercode,username){ //属性 this.usercode = usercode this.username = username //方法(实例方法,通过对象调用) this.doSome = function(){ console.log(username + " doSome.....") } //静态方法(直接类名调用,但也需要先实例化对象,否则会报错) User.doOther = function(){ console.log("user doOther.....") } } //给User类添加扩展方法(动态方法,针对实例对象,需要实例对象调用) User.prototype.getUsername = function(){ return this.username }
AJAX跨域问题
跨域
-
跨域是指从一个域名的网页发送请求给另一个域名的资源
-
通过超链接、表单提交、图片资源获取src、获取js文件、window.location.href的方式进行跨域是不存在问题的
-
发送ajax请求跨域访问,会被同源策略阻止
-
同源策略是指一段脚本只能读取来自同一个来源的窗口和文档的属性,同源就是协议、域名和端口都相同
-
同源策略是浏览器的一种安全策略,有利于保护网站信息
-
只要协议、域名和端口有一个不一致,则是不同源
-
同源XMLHttpRequest对象可以共享,不同源XMLHttpRequest对象不可以共享
AJAX跨域解决方案
-
方案1:设置相应头
-
核心原理:跨域访问的资源允许你跨域访问
-
response.setHeader("Access-Control-Allow-Origin","*")//允许所有 response.setHeader("Access-Control-Allow-Origin","http://localhost:8080")//允许某个
-
-
方案2:jsonp
-
jsonp:json with padding
-
jsonp不是一个真正的ajax请求,可以完成ajax的局部刷新效果,并且可以解决跨域问题,可以说jsonp是一种类ajax请求的机制
-
jsonp解决跨域时,只支持GET请求,不支持POST请求
-
由Tomcat服务器1的a项目发送跨域请求到Tomcat服务器2的b项目
<!--<script type="text/javascript" src="http://localhost:8081/b/json?username='响希'"></script> --> <script type="text/javascript"> window.onload = () => { //创建script元素对象 let htmlScriptElement = document.createElement("script") //设置script的type属性 htmlScriptElement.type = "text/javascript" //设置script的src属性 htmlScriptElement.src = "http://localhost:8081/b/jsonp?username='响希'" //将script对象添加到body标签中(加载script) document.getElementByTagName("body")[0].appendChild(htmlScriptElement) } </script>
-
-
方案3:jQuery封装的jsonp
-
jQuery中的jsonp是手写的jsonp代码的高度封装,底层原理相同,使用前需要引入jQuery库的js文件
-
核心代码
$.ajax({ type : "GET", url : "跨域url", dataType : "jsonp",//指定数据类型 jsonp : "func", //指定参数名(不设置时,默认为"callback") jsonpCallback : "sayHello"//指定回调函数名(不设置时,jQuery会自动生成一个随机的回调函数名,并且这个回调函数还会自动调用success的回调函数) })
-
-
方案4:代理机制(httpclient)
-
使用java程序发送GET/POST请求(HTTP请求)
-
第一种方案:使用JDK内置的API(java.net.URL...),这些API是可以发送HTTP请求的
-
第二种方案:使用第三方的开源组件,比如:apache的httpclient组件
-
-
在java程序中,使用httpclient组件可以发送http请求
-
使用httpclient组件,需要先将相关的jar包引入到项目当中
-
-
-
方案5:nginx反向代理