一、概述
(一)概念:
1.概念:
- Ajax是一种web应用技术,可以借助客户端脚本与服务器端应用进行异步通讯,获取服务器数据以后,进行局部刷新进而提高数据响应和渲染速度。
2.开发基础:
- Ajax的开发基础:是借助客户端脚本语言如:JavaScript。
(二)适用场景
- Ajax技术可以在底层与服务器端进行异步通信,同时,又可以完成对客户端局部的结果输出显示。因此,客户端局部所需的数据需要改变,且又不影响客户端其它操作时,则可以使用Ajax技术。
(三)优缺点
- 优点:
- Ajax可以仅向服务器发送请求,在客户端使用JavaScript处理服务器端响应,取回必要的数据,因此,客户端与服务器端交换数据少,服务器端响应速度,及JavaScript处理速度都更快。
- Ajax可以对客户端进行局部刷新,即针对特定元素(标签更新数据),因此,渲染客户端速度快。
- Ajax可以在底层与服务器异步通信,因此,在与服务器端通信时,不影响客户端其它操作。
- 缺点:Ajax不能直接进行跨域访问。即不能从一个网站访问别一个网站。
二、Ajax开发基础
(一)Ajax请求类型
1.get请求
2.post请求
3.delete请求
4.put请求
(二)Ajax执行流程:
- 所有Ajax请求的基于都是Html标签事件(Javascript的DOM事件),通过Javascript,调用XMLHttpRequest对象,完成与服务器端请求,并将各应结果输出到浏览器特定的Html标签,完成对网页的局部渲染更新。
(三)开发步骤
- 第一步:创建对象:
- 方法:
var xhr = new XMLHttpRequest();
-
- 说明:
- 部分属性:XMLHttpRequest {readyState: 0, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, onreadystatechange: ƒ, …}
- readyState状态类别:
- 说明:
未初始化:readyState=0
此阶段确认XMLHttpRequest对象是否创建,并为调用open()方法进行未初始化作好准备。值为0表示对象已经存在,否则浏览器会报错--对象不存在。
载入:readyState=1
此阶段对XMLHttpRequest对象进行初始化,即调用open()方法,根据参数(method,url,true)完成对象状态的设置。并调用send()方法开始向服务端发送请求。值为1表示正在向服务端发送请求。
载入完成: readyState=2
此阶段接收服务器端的响应数据。但获得的还只是服务端响应的原始数据,并不能直接在客户端使用。值为2表示已经接收完全部响应数据。并为下一阶段对数据解析作好准备。
交互: readyState=3
此阶段解析接收到的服务器端响应数据。即根据服务器端响应头部返回的MIME类型把数据转换成能通过responseBody、responseText或responseXML属性存取的格式,为在客户端调用作好准备。状态3表示正在解析数据。
完成readyState=4
此阶段确认全部数据都已经解析为客户端可用的格式,解析已经完成。值为4表示数据解析完毕,可以通过XMLHttpRequest对象的相应属性取得数据。
- 第二步:设置监听状态
- 方法:
xhr.onreadystatechange = function ()
{
if(xhr.readyState==4&&xhr.status==200)
{
document.getElementById("shwRslt").innerText = xhr.responseText;
}
}
- 说明:
- readyState状态类别:
- function(){}的作用,是对不同的服务器响应的不同状态进行处理。该函数是一个回调函数。该函数会readyState改变时被xhr对象调用。
- xhr.onreadystatechange在ajax中被定义为一个无参函数。
- 此步骤是对xhr对象的初始化部分,它修改了XMLHttpRequest构造对象不能提供值的onreadystatechange属性。
未初始化:readyState=0
此阶段确认XMLHttpRequest对象是否创建,并为调用open()方法进行未初始化作好准备。值为0表示对象已经存在,否则浏览器会报错--对象不存在。
载入:readyState=1
此阶段对XMLHttpRequest对象进行初始化,即调用open()方法,根据参数(method,url,true)完成对象状态的设置。并调用send()方法开始向服务端发送请求。值为1表示正在向服务端发送请求。
载入完成: readyState=2
此阶段接收服务器端的响应数据。但获得的还只是服务端响应的原始数据,并不能直接在客户端使用。值为2表示已经接收完全部响应数据。并为下一阶段对数据解析作好准备。
交互: readyState=3
此阶段解析接收到的服务器端响应数据。即根据服务器端响应头部返回的MIME类型把数据转换成能通过responseBody、responseText或responseXML属性存取的格式,为在客户端调用作好准备。状态3表示正在解析数据。
完成readyState=4
此阶段确认全部数据都已经解析为客户端可用的格式,解析已经完成。值为4表示数据解析完毕,可以通过XMLHttpRequest对象的相应属性取得数据。
- 第三步:开启连接
- 语法:
xhr.open("GET", `/ipt?name=${name}`, true);
- 说明:
- 实参true:对应boolean类型形参async。作用:指定与服务器通讯方式。
- 实参true:指定异步通讯。
- 实参false:指定同步通讯。
- 实参`/ipt?name=${name}`:对应的形参为字符串型的url,作用:指定访问servlet地址。
- 实参取值必须与method对应。
- 当method为“GET”时,url为servlet访问地址拼接?name(属性名)=值。
- 当method为“POST”时,url即为servlet访问地址。
- 实参取值必须与method对应。
- 实参“GET”:对应形参为字符串型的method,作用:指定请求方式。
- 实参:“GET”:指定请求方式为get请求。
- 实参:“POST”:指定请求方式为post请求。
- 实参true:对应boolean类型形参async。作用:指定与服务器通讯方式。
- 可选步骤:设置请求头。
- 使用时机:当Ajax为POST|PUT请求时,需要在开户连接后,使用该步骤。
- 语法:
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
- 说明:
- 目前为止:两个实参内容是固定的。
- 实参"application/x-www-form-urlencoded"对应的形参为String型value。
- 实参"Content-Type"对应的形参为String型name。
- 第四步:发送请求
- 语法:
xhr.send(String body);
- 说明:
- 形参:
- String类型的body
- 当为Get请求时,可以不传实参或实参为null。
- 当为Post请求时,实参为传递给服务器端的的数据。
- 当传递的字符串时,格式为:`name=${name}`的EL表达式。
- 形参:
JavaScript支持字符串拼接的方式:
假定:name为String类型的变量。需要将name拼接到字符串“name=”之后。
- 方式一:+运算符拼接法。
- 语法:"name="+name;
- 注意事项:该方式在字符串作为参数传递时,容易被篡改拼接内容。不安全、不推荐。
- 方式二:EL表达式拼接。JavaScript支持EL表达式
- 语法:`name=${name}`;
- 说明:``为反单引号,该方法不容易被篡改拼接内容,安全,使用JavaScript开发时推荐使用。
(三)Ajax处理Get请求与Post请求时的区别
- 区别一:传递给xhr.open()的method实参不同。
- Get请求:实参为"GET"
- Post请求:实参为"POST"
- 区别二:传递给xhr.open()的url实参不同。
- Get请求:实参为待访问servlet地址拼接参数后形成的url。
- Post请求:实参为待访问servlet地址。
- 区别三:是否设置请求头。
- Get请求:不需要设置请求头。
- Post请求:需要使用可选步骤设置请求头。设置时机:调用open()函数之后,send()函数之前。
- 区别四:传递给xhr.send()函数实参不同。
- Get请求:不需要传实参域传实参为null
- Post请求:需要将传给服务器端数据作为实参传递给xhr.send()。
三、Ajex关键代码封装
(一)封装的优势
- 代码的封装可以提高代码的复用性。
(二)将Ajex开发步骤封装成函数
1.Ajex开发四步封装成函数:具体代码如下:
function mtdRqst(mth,url,paramer,masync,disposeRslt)
{
const xhr = new XMLHttpRequest();
xhr.onreadystatechange=function ()
{
if(xhr.readyState == 4)
{
if(xhr.status == 200)
{
disposeRslt(xhr.responseText);
}
}
}
if(mth=="GET")
{
url= `${url}?name=${paramer}`;
paramer=null;
}
xhr.open(mth,url,masync);
if(mth=="POST")
{
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
paramer=`name=${paramer}`;
}
console.log(paramer);
xhr.send(paramer);
}
2.在业务方法中应用封装好的代码:以Post请求为例
function onClick01()
{
var mth = "POST";
var url = "/ipt";
var paramer = document.getElementById("input").value;
var masync = true;
function disposeRslt(rlt)
{
document.getElementById("shwRslt").innerHTML=rlt;
};
mtdRqst(mth, url, paramer, masync, disposeRslt);
}
3.技术要点:
- JavaScript函数声明与调用。
(三)将Ajax封装成类。
1.封装Ajax开发四步骤,代码之一如下:
(function(){
var MyAjax=function (){};
MyAjax.prototype={
myMtdRqst:function (mth,url,paramer,masync,disposeRslt)
{
const xhr = new XMLHttpRequest();
xhr.onreadystatechange=function ()
{
if(xhr.readyState == 4)
{
if(xhr.status == 200)
{
disposeRslt(xhr.responseText);
}
}
}
if(mth=="GET")
{
url= `${url}?name=${paramer}`;
paramer=null;
}
xhr.open(mth,url,masync);
console.log(url);
console.log(url);
if(mth=="POST")
{
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
paramer=`name=${paramer}`;
}
console.log(paramer);
xhr.send(paramer);
}
}
window.myajax=new MyAjax();
})();
2.业务方式中应用封装好的代码:以Post为例:
function onClick02()
{
console.log("onClick02()被调用")
var mth = "POST";
var url = "/ipt";
var paramer = document.getElementById("input").value;
var masync = true;
function disposeRslt(rlt)
{
document.getElementById("shwRslt").innerHTML=rlt;
};
myajax.myMtdRqst(mth, url, paramer, masync, disposeRslt);
}
3.技术要点:
- Javascript类的声明,创建,使用。
四、Ajax在JQuery中的应用
(一)Ajax为什么能在JQuery中使用
- Ajax技术是借助客户端脚本语言如:JavaScript与服务器端进行通讯的,而JQuery是封装了Javascript的框架,因此,Ajax可以借助JQuery进行开发。
(二)Ajax基于JQuery开发工具
1.$.ajax()
- 作用:JQuery对ajax开发步骤及细节的封装,实现ajax的所有功能(异步通信,局部刷新)
- 使用方法:$.ajax()有两种调用方式:
- 方式一:$.ajax(url[,Settings]);
- 方式二:$.ajax(Settings);
- 示例:
$.ajax({
/*,async: false/ture; 设置同步/异步*/
type: "post",
url: "/logs/getlogs",/*访问的目标*/
data: param ,/*向后端传递的参数,当param是数组时,需要把param转换成Json字符串,才能传递给服务器。*/
/*请求的类型:get、post、put、 delete*/
contentType: "application/x-www-form-urlencoded;charset=UTF-8",/*当设置编码格式的,通常是配合post;当向服务器传递的是Json字符串时,该值为:application/json*/
dataType: "json",/*服务端返回的数据的格式:xml、html、script、json、jsonp,如果不指定
ajax会智能判断,但是影响效率。*/
/*成功后的回调函数!*/
success: (rlt)=>{
console.log(rlt);
},
/*失败后的回调函数!*/
error: ()=>{
console.log("失败");
}
})
- 说明:
- 参数格式:$.ajax()的实参实质上是一个JS对象,内部属性为key-value结构
- 常用属性:
- type:指定请求方式;属性值:为字符串,可以省略"",支持:POST|GET|所有浏览器都技术,PUT|DELETE部分浏览器支持;默认值为"GET"。
- url:指定访问的资源路径。属性值:字符串型。
- data:发送到服务器的数据。属性值:必须为字符串型值,如果是基本数据类型,则会自动转换成字符串;如果是数组,则需要通过数组的成员方法toString()转换成字符串。如果是Josn对象,则需要通过JSON.Stringify(param)转换成字符串。
- dataType:指定预期服务器返回的数据类型;属性值:字符串类型的xml|json|script|html|text。默认为:Intelligengt Guess(xml,json,script,or html)。当不指定时,JQuery将自动根据http响应信息自动判断。
- 具体处理如图所示:
-
-
-
onreadystatechange = function () {
-
-
-
-
- contentType:指定发送信息到服务器时内容编码格式;属性值:字符串型,默认值:application/x-www-form-urlencoded; charset=UTF-8
- success:指定成功后的回调函数。属性值:函数型: Function( Object data, String textStatus, jqXHR jqXHR )。
- 这个函数传递3个参数:data:从服务器返回的数据,并根据dataType参数进行处理后的数据,textStatus:一个描述状态的字符串;还有 jqXHR(在jQuery 1.4.x前为XMLHttpRequest) 对象 。在jQuery 1.5, 成功设置可以接受一个函数数组。每个函数将被依次调用。这是一个 Ajax Event
- 其中:textStatus,jqXHR可以省略。
- async:指定此次Ajax请求是否为异步。属性值:Boolean值,false:同步、true:异步;默认值:true。
-
2.$.get()
- 函数原型:
jQuery.get( url [, data ] [, success(data, textStatus, jqXHR) ] [, dataType ] )
- 使用说明:
- 参数说明url类型: String一个包含发送请求的URL字符串
data类型: PlainObject, String发送给服务器的字符串或Key/value键值对。
success(data, textStatus, jqXHR)类型: Function()当请求成功后执行的回调函数。
dataType类型: String从服务器返回的预期的数据类型。默认:智能猜测(xml, json, script, 或 html)。使用方式示例:
3.$.post()
- 函数原型:
jQuery.post( url [, data ] [, success(data, textStatus, jqXHR) ] [, dataType ] )
- 使用说明:
- 参数说明:url类型: String一个包含发送请求的URL字符串
- data类型: PlainObject, String发送给服务器的字符串或Key/value键值对。
- success(data, textStatus, jqXHR)类型: Function()当请求成功后执行的回调函数。
- dataType类型: String从服务器返回的预期的数据类型。默认:智能判断(xml, json, script, or html)。
- 使用示例:
Example: 请求 test.php 页面, 但是忽略返回结果
1 | $.post("test.php"); |
Example: 请求 test.php 页面 并且发送url参数(虽然仍然忽视返回的结果)。
1 | $.post("test.php", { name: "John", time: "2pm" } ); |
Example: 传递数组形式data参数给服务器 (虽然仍然忽视返回的结果)。
1 | $.post("test.php", { 'choices[]': ["Jon", "Susan"] }); |
Example: 使用Ajax请求发送表单数据。
1 | $.post("test.php", $("#testform").serialize()); |
Example: Alert 从 test.php请求的数据结果 (HTML 或者 XML,取决于返回的结果)。
1 2 3 | $.post("test.php", function(data) { alert("Data Loaded: " + data); }); |
Example: Alert 从 test.cgi请求并且发送url参数的数据结果 (HTML 或者 XML,取决于返回的结果)。
1 2 3 4 | $.post("test.php", { name: "John", time: "2pm" }, function(data) { alert("Data Loaded: " + data); }); |
Example: 得到test.php的内容,存储在一个 XMLHttpResponse 对象中并且运用 process() JavaScript函数。
1 2 3 4 5 6 | $.post("test.php", { name: "John", time: "2pm" }, function(data) { process(data); }, "xml" ); |
Example: Posts to the test.php page and gets contents which has been returned in json format (<?php echo json_encode(array("name"=>"John","time"=>"2pm")); ?>).
1 2 3 4 5 | $.post("test.php", { "func": "getNameAndTime" }, function(data){ console.log(data.name); // John console.log(data.time); // 2pm }, "json"); |
Example: 用ajax传递一个表单并把结果在一个div中
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 | <!DOCTYPE html> <html> <head> <script src="https://code.jquery.com/jquery-latest.js"></script> </head> <body> <form action="/" id="searchForm"> <input type="text" name="s" placeholder="Search..." /> <input type="submit" value="Search" /> </form> <!-- the result of the search will be rendered inside this div --> <div id="result"></div> <script> /* attach a submit handler to the form */ $("#searchForm").submit(function(event) { /* stop form from submitting normally */ event.preventDefault(); /* get some values from elements on the page: */ var $form = $( this ), term = $form.find( 'input[name="s"]' ).val(), url = $form.attr( 'action' ); /* Send the data using post and put the results in a div */ $.post( url, { s: term }, function( data ) { var content = $( data ).find( '#content' ); $( "#result" ).empty().append( content ); } ); }); </script> </body> </html> |
4.$.getJSON()
- 函数原型:
jQuery.getJSON( url [, data ] [, success(data, textStatus, jqXHR) ] )
- 使用说明:
- 参数url类型: String一个包含发送请求的URL字符串
- data类型: PlainObject发送给服务器的字符串或Key/value键值对。
- success(data, textStatus, jqXHR)类型: Function()当请求成功后执行的回调函数。
- 使用示例:
<script>
$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?",
{
tags: "mount rainier",
tagmode: "any",
format: "json"
},
function(data) {
$.each(data.items, function(i,item){
$("<img/>").attr("src", item.media.m).appendTo("#images");
if ( i == 3 ) return false;
});
});</script>
5..load()
- 函数原型:
.load( url [, data ] [, complete(responseText, textStatus, XMLHttpRequest) ] )
- 使用说明:
- 参数:url类型: String一个包含发送请求的URL字符串
- data类型: PlainObject, String向服务器发送请求的Key/value参数,例如{name:"",age:23}
- complete(responseText, textStatus, XMLHttpRequest)
- 类型: Function()当请求成功后执行的回调函数。
- 使用示例:
Example: 在一个有序列表中,加载主页的页脚导航。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <!DOCTYPE html> <html> <head> <style> body{ font-size: 12px; font-family: Arial; } </style> <script src="https://code.jquery.com/jquery-latest.js"></script> </head> <body> <b>Footer navigation:</b> <ol id="new-nav"></ol> <script> $("#new-nav").load("/ #jq-footerNavigation li"); </script> </body> </html> |
Example: 显示一个信息如果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 | <!DOCTYPE html> <html> <head> <style> body{ font-size: 12px; font-family: Arial; } </style> <script src="https://code.jquery.com/jquery-latest.js"></script> </head> <body> <b>Successful Response (should be blank):</b> <div id="success"></div> <b>Error Response:</b> <div id="error"></div> <script> $("#success").load("/not-here.php", function(response, status, xhr) { if (status == "error") { var msg = "Sorry but there was an error: "; $("#error").html(msg + xhr.status + " " + xhr.statusText); } }); </script> </body> </html> |
(三)使用ajax发送put/delete请求
1.put请求:服务器端是SpringBoot的项目时
- 使用示例:
$.ajax({
type: "put",
url: url,
data: JSON.stringify(menuInfo),
dataType: "json",
contentType: "application/json",
success: (rlt)=>{
let icon = 2
if(1 == rlt.status)
{
icon = 1;
}
layer.msg(rlt.msg, {icon: icon, time: 2500});
returnToMenuManagerPage();
}
})
-
- 说明:
- 当使用put请求向服务器端发送参数为js对象时,需要将该对象转换成json字符串,方法如下所示。
- contentType:必须设置为application/json[;charset=UTF-8]
- 服务器端则需要使用@RequestBody描述controller方法中接收实参的形参。
(四)Ajax传递数据。
1.Ajax传递数据的格式:仅支持普通及JSON字符串。
2.Ajax处理JavaScript数组参数时,必须转换成字符串。
- 语法:arrName.toString();
- 说明:该方法是Object的类的方法,java中的数组是Object的子类,此处同样适用于JScript。
- 适用情形:当服务器端的Controller接收的是某类型的可变参数时,使用此方法。
3.使用Ajax传递封装类对象数组:
- 客户端Ajax请求设置:
- 设置请求方式为post,但不能调用$.post()方法。
- 将参数转化成Json格式的字符串。
- 方法:
data: JSON.stringify(param)
-
- 必须指定dataType参数的值为:json
- 必须指定contextType参数的值为:application/json,charset=utf-8
- 指定传递参数,并转换成Json格式字符串:JSON.stringigy(实参)。
- 客户端调用Ajex方式:
- 客户端参数格式:
- 必须牢记:参数对象的属性名必须与封装类的属性名一致,属性个数与封装类的属性个数可以不一致。
- 服务器端接收参数设置:
- 使用封装类做为形参
- 使用注解@RequestBody描述该形参。
- 具体方式:
五、Ajax的变种:axios
六、Ajax常见错误解决
1.以POST请求方式向服务器端传递参数失败。
- 第一步:检查访问地址是否正确。不正确:改动地址。
- 第二步:如果地址正确,检查客户端与服务器参数名是否相同。不相同:改成相同。
- 第三步:如果参数相同:检查参数格式是否正确。不正确:改成正确的参数格式。
- 参数格式:参数名=参数值。如:`name=${name}`;
- 第四步:如果参数格式正确:检查是否设置请求头或请求头格式是否正确:
- 原因:POST请求方式必须在open()和send()函数之间加入设置请求头方法。
- 请求头设置方法:xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
2.通过$.get()|$.post()|$.getJSON()|$.ajax()等传递参数时,由想法不一致。
- 通过{}构造对象的方式,构造参数。
- 语法:
let paramer = {name:vlue,...,password:vlue2};
3.通过$.post()方法发送请求时,报415错误。
- 错误情形:只有以post方式发送请求时,有可能出现。
- 错误原因:前后端传递参数时,两端的对发送内容的编码格式要求不一致造成的。
- 原因原理:
- 在使用Ajax通信时,前后端都会对发送内容的编码格式进行统一约定,只有编码格式相同时,才能保证发送内容正确传递与接收。
- 而Ajax通信时,有两种内容传递方式:1.普通字符串;2.Json格式字符串。
- 普通字符串常用于传递基本数据类型及其包装类型的参数传递。
- Json格式字符串常用于传递Json对象。
- 使用两种字符串发送参数时,编码格式不一样:
- 普通字符串的contentType:"application/x-www-form-urlencoded".也是Ajax传递参数的默认格式。
- json格式字符串的contentType:"application/json;charset=utf-8"。
- 使用两种字符串发送参数时,服务器端接收方式不一样:
- 普通字符串:后端形参名与前端形参名相同即可,且数据类型即为基本数据类型及其包装类型即可,不需要额外的设置,即不需要以任何注解修饰。
- json格式字符串:后端一般使用封装类做为形参,形参属性名与前端属性名一致。必须使用@RequestBody注解描述该形参;该注解告诉后端,前端以application/json格式发送内容,即使用Json格式的字符串发送的参数。
- 关于@RequestBody见:@RequestBody的使用-CSDN博客
- 解决方法:
- 检查前后端内容编码格式是否一至:
- 前端设置了contentType:"application/json",后端必须使用@RequestBody注解描述形参。
- 前端没有设置contentType,则后端不能使用@RequestBody注解描述形参。
- 检查前后端内容编码格式是否一至:
4.服务器404错误:
- 含义:请求资源不存在。
- 原因:Ajax访问的url服务器端不存在。
- 解决方式:检查Ajax访问的url与@RequestMapping()中的实参是否一致。
5.服务器500错误:
- 含义:服务器端错误。
- 原因:通过返回页面方法的返回值没有找到目标资源。
- 解决方法:检查ctrll的return的路径是否正确。