Ajax
1. JavaScript中的Ajax
1.1 功能
实现网页的动态展示。刷新网页中的部分页面内容,又不引起整个页面的刷新。
- 完整代码:
let xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.onreadystatechange = function () {
if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200){
var text = xmlHttpRequest.responseText;//服务器返回的字符串
console.log(text)
//ToDo
}
}
//GET请求发送数据:getText="/资源路径?key1=value&key2=value"
xmlHttpRequest.open("GET",getText,true);
xmlHttpRequest.send();
1.2 步骤详解(GET请求)
- 创建XMLHttpRequest对象
let xmlHttpRequest = new XMLHttpRequest();
- 状态码发生改变
onreadystatechange
xmlHttpRequest.readyState
返回0-4,5个值,代表xmlHttpRequest
对象的5种不同状态:
0:xmlHttpRequest
对象的未初始化状态。这个值检测不到;
1:xmlHttpRequest
对象使用open方法,创建了Http请求;
2:xmlHttpRequest
对象使用send方法,处于发送数据状态;
3: 客户端已经返回数据,xmlHttpRequest
对象正在接收数据的状态;
4:数据接收完毕
xmlHttpRequest.status
返回响应状态码,200表示响应成功
xmlHttpRequest.responseText
返回Response响应的字符串。
xmlHttpRequest.onreadystatechange = function () {
if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200){
var text = xmlHttpRequest.responseText;//服务器返回的字符串
//ToDo
}
}
- 初始请求数据
XMLHttpRequest.open(method,URL,flag,name,password);
参数:
- method:请求方式GET | POST
- URL:路径
- flag: true异步请求;false同步请求。默认为true
- name:服务器用户名
- password: 服务器密码同步:在第4步发送请求之后,必须等待服务器将数据返回,在此期间不能执行其他任务。
异步:在第4步发送请求之后,执行其他任务,无需等待数据返回。
xmlHttpRequest.open("get",getText,true);
- 发送请求
xmlHttpRequest.send();
1.3 通过POST请求发送表单
与GET请求有两个不同的地方
- 需要设置请求头:
代码必须在open方法和send方法中间
xmlHttpRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8")
- 发送数据的位置
xmlHttpRequest.send("key1=value&key2=value");
1.3.1 POST请求时发送到服务器的各种数据格式
- JSON数据格式
application/json
xhr.setRequestHeader("Content-type","application/json; charset=utf-8");
- 提交 form 表单
application/x-www-form-urlencoded
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");
- 通过form表单发送文件
multipart/form-data
xhr.setRequestHeader("Content-type", "multipart/form-data; charset=utf-8");
- 发送数据为xml格式
text/xml
xhr.setRequestHeader("Content-type", "text/xml; charset=utf-8");
1.4 返回的json格式如何处理
服务器返回的数据都是字符串格式,处理方法:
- eval方法
var jsonObj = eval('('+jsonStr+')');//将json字符串jsonStr转换为jasn对象
var value = jsonObj.key1;//返回json对象中键值为key1的值
- JSON.prse
var jsonObj = JSON.parse(jsonStr);//将json字符串jsonStr转换为jasn对象
1.5 通过ajax发送请求和接收响应时乱码问题
- Tomcat 10 没有任何乱码问题
- Tomcat 9 及以下
- Get 请求:Response响应返回中文乱码
解决办法,服务器端加入以下代码:
response.setContentType("text/html;charset=UTF-8");
- POST请求:在请求和响应中文时都有乱码问题
解决办法:
request.setCharacterEncoding(‘UTF-8’);//解决请求乱码
response.setContentType("text/html;charset=UTF-8");//解决响应乱码
2. JQuery中的Ajax
详细的讲解
第一种:(参数最少的写法)
$.ajax({
url:"路径",
data: {
id: 1,
},
success:function (data) {
$.each(data,function (i,n) {
// each可以循环json格式的字符串,i为index,n为json的数据,取值:n.name
})
}
})
$.each(data,function (i,n)
的参数:
- data为一维的数组或json对象时:
i
是key,n
是value - data为二位的数组或json对象是List集合时:
i
是下标,n
是data[i]
参数名 | 类型 | 描述 |
---|---|---|
url | String | (默认: 当前页地址) 发送请求的地址。 |
type | String | (默认: “GET”) 请求方式 (“POST” 或 “GET”), 默认为 “GET”。注意:其它 HTTP 请求方法,如 PUT 和 DELETE 也可以使用,但仅部分浏览器支持。 |
async | Boolean | (默认: true) 默认设置下,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为 false。注意,同步请求将锁住浏览器,用户其它操作必须等待请求完成才可以执行。 |
contentType | String | (默认: “application/x-www-form-urlencoded”) 发送信息至服务器时内容编码类型。默认值适合大多数应用场合。告诉服务器从浏览器提交过来的数据格式。 |
data | Object、String | 发送到服务器的数据。json格式 |
dataType | String | 预期服务器返回的数据类型。json、string |
error | Function | (默认: 自动判断 (xml 或 html)) 请求失败时将调用此方法。这个方法有三个参数:XMLHttpRequest 对象,错误信息,(可能)捕获的错误对象。 |
success | Function | 请求成功后回调函数。这个方法有两个参数:服务器返回数据,返回状态 |
beforeSend | Function | 请求发起前执行 |
complete | Function | 请求完成后执行,无论成功与否 |
- 第二种
$.get(“url”,{ data(key:value) },callback,“type”);
$.post(“路径”,{ “数据名”:数据 },function(返回的数据){ 执行代码 },“数据格式”)
默认数据格式为json,可省略,get请求最简化写法:
$.get("路径",function(返回的数据){ 执行代码 })
参数名称 | 类型 | 说明 |
---|---|---|
url | String | 请求HTML页的URL地址 |
data(可选) | Object | 发送到服务器的key/value数据会作为字符串附加到请求的URL中 |
callback(可选) | Function | 请求成功时的回调函数,有两个参数:返回的数据,请求状态 |
type(可选) | String | 服务器返回内容的格式:xml、html、script、json、text、default |
3. 跨域请求
Ajax发送跨域请求时会被浏览器的同源策略(CORS)阻止,这是浏览器的安全策略。
总结:实现跨域请求必须服务器端配合,浏览器端无法单独实现跨域请求
示例
a站点:http://localhost:8080/a/
b站点:http://localhost:8081/b/
从a站点发送跨域请求到b站点,浏览器报错:
Access to XMLHttpRequest at 'http://localhost:8081/b/hello' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
什么是同源?
协议一致、域名一致、端口号一致。
3.1 在servlet端设置响应头,解决Ajax跨域访问
要访问的资源允许跨域访问。
//允许某个站点可以对本地资源跨域访问
response.setHeader("Access-Control-Allow-Origin","http://localhost:8080");
// 允许所有站点可以对本地资源跨域访问
response.setHeader("Access-Control-Allow-Origin","*");
3.2 jsonp,解决Ajax跨域访问
- jsonp不是Ajax请求,通过代码实现了类似Ajax局部刷新的效果。
- jsonp是利用了<script>标签的
src
属性。 - 当
script
加载时,会将src
属性的值所指向的文件内容作为script
代码执行,实现ajax的效果。 - 只能实现get请求。
3.2.1 简单示例
b中servlet返回的字符串,会在a的页面中当作script代码执行
a的web
<script type="text/javascript" src="http://localhost:8081/b/AjaxJsonp1"></script>
b的servlet
@WebServlet("/AjaxJsonp1")
public class AjaxJsonp1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().print("alert(\"Jsonp1!\")");
}
}
3.2.2 复杂示例
执行过程
- 页面加载完毕后,点击
button
按钮- 在
body
中增加script
元素script
元素加载时会加载自己的src
属性,src
属性指向b站点的ajaxjsonp2,并且通过get方法传递值fun=sayHello
- b 站点获取请求中的值
sayHello
,并返回了字符串sayHello({{"username":"jackson"}})
- 返回的字符串会被
script
元素当作script代码执行。- 执行
sayHello(data)
方法
a站点中的页面
<html>
<head>
<title>Title</title>
</head>
<body>
<script type="text/javascript">
function sayHello(data){
// 获取json字符串中的key对应的value,添加到div1中
document.getElementById("div1").innerHTML = data.username
}
</script>
<script type="text/javascript">
window.onload = function () {
document.getElementById("btn").onclick = () => {
// 创建script元素
const htmlScriptElement = document.createElement(`script`)
// 设置script的type属性
htmlScriptElement.type = "text/javascript"
// 设置script的src属性,注意:通过get方法传入了参数fun=sayHello
htmlScriptElement.src = "http://localhost:8081/b/ajaxjsonp2?fun=sayHello"
// 将script元素添加到body中
document.getElementsByTagName("body")[0].appendChild(htmlScriptElement)
}
}
</script>
<button id="btn">通过jsonp调用方法</button>
<div id="div1"></div>
</body>
</html>
b站点中的servlet
@WebServlet("/ajaxjsonp2")
public class AjaxJsonp2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// get传入参数,获取参数的值
String fun = request.getParameter("fun");
// 返回的值是字符串
response.getWriter().print(fun + "({\"username\":\"jackson\"})");
}
}
页面点击button后的代码:
<html>
<head>
<title>Title</title>
</head>
<body>
<script type="text/javascript">
function sayHello(data){
// 获取json字符串中的key对应的value,添加到div1中
document.getElementById("div1").innerHTML = data.username
}
</script>
<script type="text/javascript">
window.onload = function () {
document.getElementById("btn").onclick = () => {
// 创建script元素
const htmlScriptElement = document.createElement(`script`)
// 设置script的type属性
htmlScriptElement.type = "text/javascript"
// 设置script的src属性,注意:通过get方法传入了参数fun=sayHello
htmlScriptElement.src = "http://localhost:8081/b/ajaxjsonp2?fun=sayHello"
// 将script元素添加到body中
document.getElementsByTagName("body")[0].appendChild(htmlScriptElement)
}
}
</script>
<button id="btn">通过jsonp调用方法</button>
<-- dia-->
<div id="div1">jackson</div>
<-- 点击button后会在body最后增加子元素 script,script元素在加载时会加载src的属性值-->
<script type="text/javascript" src="http://localhost:8081/b/ajaxjsonp2?fun=sayHello"></script>
</body>
</html>
3.3 jQuery封装的jsonp
- jQuery封装的jsonp看似与ajax一样,但它只是使用了ajax的外壳
dataTape
属性值:jsonp
- 在发送请求时浏览器中请求url:请求 URL:
http://localhost:8081/b/ajaxjson3?callback=jQuery36007791340332230894_1656146765961&_=1656146765962
,jquery自动生成键值对,键的名字默认为callback
,键值对的默认值为随机字符串,并通过get方法传递给后台。后面的_=1656146765962
为时间戳,防止浏览器读取缓存。- servlet中需要获取该键值对的
value
,然后返回给浏览器。返回的数据:jQuery36007791340332230894_1656146765961({"username":"jackson"})
- 可以看出jquery实现jsonp和上面3.2.2中使用的方法是一样的,jquery把方法名和方法都进行了优化。
a站点网页
<html>
<head>
<title>Title</title>
</head>
<body>
<script type="text/javascript" src="js/jquery-3.6.0.js"></script>
<script type="text/javascript">
$(function () {
$("#btn").click(function () {
$.ajax({
type: "GET",
url: "http://localhost:8081/b/ajaxjson3",
dataType: "jsonp",// 返回数据的格式
success: function (data) {// data:返回的数据
$("#div1").html(data.username)
}
})
})
})
</script>
<button id="btn">jQuery实现jsonp</button>
<div id="div1"></div>
</body>
</html>
b站点servlet
@WebServlet("/ajaxjson3")
public class AjaxJsonp3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// jquery在get请求中添加键值对,key是callback,value为随机字符串
String callback = request.getParameter("callback");
response.getWriter().print(callback+"({\"username\":\"jackson\"})");
}
}
- a站点页面中ajax的另一种写法
- ajax发送请求时,请求 URL:
请求 URL: http://localhost:8081/b/ajaxjson4?fun=sayHello&_=1656148497823
- 不使用默认的参数名
callback
,指定为fun
- 不使用默认的回调函数
success
,指定回调函数为sayHello
<html>
<head>
<title>Title</title>
</head>
<body>
<script type="text/javascript" src="js/jquery-3.6.0.js"></script>
<script type="text/javascript">
function sayHello(data){
$("#div1").html(data.username)
}
$(function () {
$("#btn").click(function () {
$.ajax({
type: "GET",
url: "http://localhost:8081/b/ajaxjson4",
dataType: "jsonp",// 指定数据类型为jsonp
jsonp:"fun", // 指定GET请求时参数的key为callback
jsonpCallback:"sayHello" // 指定jsonp的回调函数为sayHello
})
})
})
</script>
<button id="btn">jQuery实现jsonp</button>
<div id="div1"></div>
</body>
</html>
b站点中的servlet
@WebServlet("/ajaxjson4")
public class AjaxJsonp4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String funName = request.getParameter("fun");
response.getWriter().print(funName+"({\"username\":\"jackson\"})");
}
}