本文已参与「新人创作礼」活动,一起开启掘金创作之路。
目录
一.简介
全称:Asynchronous JavaScript And XML,就是异步的JS和XML。
编辑
编辑
AJAX不是新的编程语言,而是一种将现有的标准组合在一起使用的方式。
最初AJAX在进行数据交换时用的是XML,服务端给客户端返回结果是就是返回XML格式字符串,JS把数据从XML中提取出来做处理。
现在JSON替代了XML。
1.AJAX优点
无刷新获取数据。刷新式获取数据时整个页面的资源都要请求,重复请求资源会造成浪费。
无刷新能提高用户体验,使操作更加流畅。
允许你根据用户事件来更新部分页面内容(用户事件比如鼠标事件,键盘事件),可以根据用户在特定事件下,向服务器发送请求发送请求来获取数据。
2.AJAX缺点
没有浏览历史和回退
存在跨域问题
SEO(Search Engine Optimization 搜索引擎优化)不友好
3.HTTP相关知识
编辑
General:常规的信息。
Response Hearders 响应头和响应头的内容
Request Headers 请求头和请求行的信息
Query String Parameters 可查看返回到页面中request或session等的一些参数的值
Response 响应体的内容
二.第一个AJAX程序
1.使用AJAX需要和后端交互,先搭建服务器。
Ajax需要需要向服务器发送请求,这里用Express框架创建后端。
1.在终端中输入命令行下载express相关的文件
编辑
编辑
2.创建一个js文件,编写后端的代码
//1.引入express const express = require('express'); //2.创建应用对象 const app = express(); //3.创建路由规则,request对请求报文封装,response对响应报文封装 app.get('/',(request,response)=>{ //设置响应 response.send('HELLO EXPRESS'); }); //4.监听端口,启动服务 app.listen(8000,()=>{ console.log("服务器启动,8000端口监听中.."); });
3.运行这个js文件,启动服务器
编辑
4.查看服务器启动结果
监听器在控制台输出
编辑
尝试访问服务器资源
编辑
其他
Ctrl+C:关闭服务器端口
目录结构
编辑
2.用AJAX发请求
2.1GET请求
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> #result{ width: 200px; height: 100px; border:solid 1px #90b; } </style> </head> <body> <button>点击发送请求</button> <div id="result"></div> <script> //获取事件源 //const修饰的变量的值不可变 const btn = document.querySelector('button'); const result = document.querySelector('#result'); //给btn设置事件 btn.onclick = function (){ //1.创建对象 const xhr = new XMLHttpRequest(); //2.初始化,设置请求的方法和url xhr.open('GET','http://127.0.0.1:8000/server'); //3.发送 xhr.send(); //4.事件绑定 处理服务端返回的结果 //on 当..时候 /* readystate是xhr对象中的属性,表示状态 0 1 2 3 4 0表示未初始化,最初始的状态就是0 1表示open方法已经调用完毕 2表示send方法已经调用完毕 3服务端返回了部分结果 4表示服务端返回了所有的结果 change 改变 */ //当状态改变的时候触发,也就是说会触发四次 xhr.onreadystatechange = function (){ //判断(服务器返回了所有的结果) if(xhr.readyState === 4){ //判断响应的状态码 200 404 500... if(xhr.status >= 200 &&xhr.status <300){ //处理结果 行,头 空行 体 //1.响应 console.log(xhr.status);//状态码 console.log(xhr.statusText);//状态字符串 console.log(xhr.getAllResponseHeaders());//所有的响应头 console.log(xhr.response);//响应体 //设置result的文本 result.innerHTML = xhr.response; }else{ } } } } </script> </body> </html>
//1.引入express const server = require('express'); //2.创建应用对象 const app = server(); //3.创建路由规则,request对请求报文封装,response对响应报文封装 app.get('/server',(request,response)=>{ //设置响应头 设置允许跨域 //name是响应头的名字,value是值,设置允许跨域^ response.setHeader('Access-Control-Allow-Origin','*'); //设置响应 response.send('HELLO AJAX'); }); //4.监听端口,启动服务 app.listen(8000,()=>{ console.log("服务器启动,8000端口监听中.."); });
open方法的第三个参数可以写true或false,默认使true,如果使true则为异步,异步方式服务器在处理响应时是可以操作页面的比如输入文本框,但同步方式时,在服务器处理请求时用户无法在客户端上操作。
2.2POST请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#result{
width: 200px;
height: 100px;
border: solid 1px #903;
}
</style>
</head>
<body>
<div id="result"></div>
<script>
const div = document.querySelector('div');
div.addEventListener('mouseover',function (){
//1.创建对象
const xhr = new XMLHttpRequest();
//2.初始化
xhr.open("POST","http://127.0.0.1:8000/server");
//3.发送
xhr.send();
//4.事件绑定
xhr.onreadystatechange = function (){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.readyState < 300){
//处理返回结果
div.innerHTML = xhr.response;
}
}
}
});
</script>
</body>
</html>
//1.引入express
const server = require('express');
//2.创建应用对象
const app = server();
//3.创建路由规则,request对请求报文封装,response对响应报文封装
app.get('/server',(request,response)=>{
//设置响应头 设置允许跨域
//name是响应头的名字,value是值,设置允许跨域^
response.setHeader('Access-Control-Allow-Origin','*');
//设置响应
response.send('HELLO AJAX');
});
app.post('/server',(request,response)=>{
//设置响应头 设置允许跨域
//name是响应头的名字,value是值,设置允许跨域^
response.setHeader('Access-Control-Allow-Origin','*');
//设置响应
response.send('HELLO AJAX POST');
});
//4.监听端口,启动服务
app.listen(8000,()=>{
console.log("服务器启动,8000端口监听中..");
});
2.3AJAX请求追加参数
xhr.open('GET','http://127.0.0.1:8000/server?a=100&b=200');
3.设置请求头中的参数和自定义请求头键值对
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> #result{ width: 200px; height: 100px; border: solid 1px #903; } </style> </head> <body> <div id="result"></div> <script> const div = document.querySelector('div'); div.addEventListener('mouseover',function (){ //1.创建对象 const xhr = new XMLHttpRequest(); //2.初始化 xhr.open("POST","http://127.0.0.1:8000/server"); //设置请求头,Content-Type设置请求体内容的类型,后面这一串是表示参数查询字符串类型 xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); //自定义响应头中的内容,一般会把身份校验的信息放上 xhr.setRequestHeader('name','myname'); //3.发送 xhr.send();//发送给服务端的数据 //4.事件绑定 xhr.onreadystatechange = function (){ if(xhr.readyState === 4){ if(xhr.status >= 200 && xhr.readyState < 300){ //处理返回结果 div.innerHTML = xhr.response; } } } }); </script> </body> </html>
//1.引入express const server = require('express'); //2.创建应用对象 const app = server(); //3.创建路由规则,request对请求报文封装,response对响应报文封装 app.get('/server',(request,response)=>{ //设置响应头 设置允许跨域 //name是响应头的名字,value是值,设置允许跨域^ response.setHeader('Access-Control-Allow-Origin','*'); //响应头 response.setHeader('Access-Control-Allow-Headers','*');//*表示所有类型的头信息都可以接受 //设置响应 response.send('HELLO AJAX'); }); //all可以接收任意类型的请求 app.all('/server',(request,response)=>{ //设置响应头 设置允许跨域 //name是响应头的名字,value是值,设置允许跨域^ response.setHeader('Access-Control-Allow-Origin','*'); response.setHeader('Access-Control-Allow-Headers','*');//*表示所有类型的头信息都可以接受 //设置响应 response.send('HELLO AJAX POST'); }); //4.监听端口,启动服务 app.listen(8000,()=>{ console.log("服务器启动,8000端口监听中.."); });
编辑
4. AJAX服务端响应JSON数据(对象)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> #result{ width: 200px; height: 100px; border: solid 1px #89b; } </style> </head> <body> <div id="result"></div> <script> const result = document.querySelector('#result'); //绑定键盘按下事件 window.onkeydown = function (){ const xhr = new XMLHttpRequest(); //设置响应体数据的类型 xhr.responseType = 'json'; xhr.open('GET','http://127.0.0.1:8000/json-server'); xhr.send(); xhr.onreadystatechange = function (){ if(xhr.readyState === 4){ if(xhr.status >= 200 && xhr.status < 300){ //1.手动对服务端返回的数据字符串转换 //let data = JSON.parse(xhr.response); //result.innerHTML = data.name; //2.还有一种方式是自动转换,需要给xhr设置responseType属性为json result.innerHTML = xhr.response.name; } } } }; </script> </body> </html>
//1.引入express const server = require('express'); //2.创建应用对象 const app = server(); app.all('/json-server',(request,response)=>{ //设置响应头 设置允许跨域 //name是响应头的名字,value是值,设置允许跨域^ response.setHeader('Access-Control-Allow-Origin','*'); response.setHeader('Access-Control-Allow-Headers','*');//*表示所有类型的头信息都可以接受 //响应一个对象数据 const data = { name:'zhou' }; //send方法里面只能接收字符串或者buffer //需要对对象进行字符串的转换 let str = JSON.stringify(data); //设置响应 response.send(str); }); //4.监听端口,启动服务 app.listen(8000,()=>{ console.log("服务器启动,8000端口监听中.."); });
服务端想要返回对象数据,将数据转换为JSON格式返回。
客户端接收对象数据,要解析JSON格式。
Java后台向HTML返回数据
PrintWriter writer = resp.getWriter(); writer.write("{"name":"z"}");
只要前端传递这种格式的字符串,就能当作JSON格式接收。
不是这种格式的字符串,只能用text格式接收了。
集合和对象可以通过下面这种方式转为这种类型的字符串
String json = mapper.writeValueAsString(p); String json = mapper.writeValueAsString(map);
集合和对象也可以直接传递给流让前端接收
ObjectMapper mapper = new ObjectMapper(); //将map交给一个流 mapper.writeValue(resp.getWriter(),map);
三.工具
自动重启服务器工具 nodemon
命令行下载安装
编辑
启动服务器
编辑
修改服务端内容后,按Ctrl+s 就会自动重新启动
四.AJAX的应用
1.Ajax请求超时与网络异常处理
客户端向客户端发请求,设定一个时间,如果这个时间过了还没有响应,就给用户一个提醒,告诉用户网络超时。
前端设置超时时间,后端设置延迟时间来演示网络延迟,当超出客户端设置的延迟时间,弹出对话框提示网络超时。
前端:timeout,ontimeout,onerror
后端:setTimeout
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> #result{ width: 200px; height: 100px; border: solid 1px #89b; } </style> </head> <body> <div id="result"></div> <script> const result = document.querySelector('#result'); //绑定键盘按下事件 window.onkeydown = function (){ const xhr = new XMLHttpRequest(); //超时设置,超过2s就认为超时,请求就会取消 xhr.timeout = 2000; //超时回调 xhr.ontimeout = function (){ alert("网络异常,请稍后再试"); }; xhr.onerror = function () { alert("你的网络出现了问题"); }; //设置响应体数据的类型 xhr.open('GET','http://127.0.0.1:8000/delay'); xhr.send(); xhr.onreadystatechange = function (){ if(xhr.readyState === 4){ if(xhr.status >= 200 && xhr.status < 300){ result.innerHTML = xhr.response; } } } }; </script> </body> </html>
const server = require('express'); const app = server(); //延时响应 app.all('/delay',(request,response)=>{ response.setHeader('Access-Control-Allow-Origin','*'); setTimeout(()=>{ response.send('HELLO AJAX POST'); },3000); }); //4.监听端口,启动服务 app.listen(8000,()=>{ console.log("服务器启动,8000端口监听中.."); });
2.Ajax取消请求
abort取消发送请求
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> #result{ width: 200px; height: 100px; border: solid 1px #89b; } </style> </head> <body> <button class="send">发送请求</button> <button class="cancel">取消请求</button> <script> const send = document.querySelector('.send'); const cancel = document.querySelector('.cancel') let xhr = null;//和var相比,let声明的变量不会被提升到函数作用域顶部 send.onclick = function (){ xhr = new XMLHttpRequest(); xhr.open('GET','http://127.0.0.1:8000/delay'); xhr.send(); xhr.onreadystatechange = function (){ if(xhr.readyState === 4){ if(xhr.status >= 200 && xhr.status < 300){ result.innerHTML = xhr.response; } } } }; cancel.onclick = function () { xhr.abort(); } </script> </body> </html>
const server = require('express'); const app = server(); //延时响应 app.all('/delay',(request,response)=>{ response.setHeader('Access-Control-Allow-Origin','*'); setTimeout(()=>{ response.send('HELLO AJAX POST'); },3000); }); //4.监听端口,启动服务 app.listen(8000,()=>{ console.log("服务器启动,8000端口监听中.."); });
2.1取消发送请求的应用
防止用户重复点请求导致服务器压力变大。
方法是当用户重复点击请求时,如果上一个请求还在,就将上一个请求取消掉。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> #result{ width: 200px; height: 100px; border: solid 1px #89b; } </style> </head> <body> <button class="send">发送请求</button> <script> const send = document.querySelector('.send'); let xhr = null;//和var相比,let声明的变量不会被提升到函数作用域顶部 //表示变量,判断是否正在发送ajax请求 let isSending = false; send.onclick = function (){ if(isSending == true) xhr.abort();//如果请求正在发送,则取消该请求,创建一个新的请求 isSending = true; xhr = new XMLHttpRequest(); xhr.open('GET','http://127.0.0.1:8000/delay'); xhr.send(); xhr.onreadystatechange = function (){ if(xhr.readyState === 4){ isSending = false; if(xhr.status >= 200 && xhr.status < 300){ result.innerHTML = xhr.response; } } } }; </script> </body> </html>
编辑
重复发送了两次请求,第一个请求就被取消了。
五.在JQuery中使用Ajax
1.发送get请求和post请求
编辑
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="http://apps.bdimg.com/libs/bootstrap/3.3.4/css/bootstrap.min.css"> <script src="jquery-3.4.1.min.js"></script> </head> <body> <div> <div class="container"> <h2 class="page-header">JQuery发送Ajax请求</h2> <button class="btn btn-primary">GET</button> <button class="btn btn-danger ">POST</button> <button class="btn btn-info">通用</button> </div> <script> $('button').eq(0).click(function () { //通过$.get去发送Ajax请求 $.get('http://127.0.0.1:8000/jQuery-server',{a:100,b:200},function (data) { console.log(data); },'json');//响应体类型为json。还有text类型 }) $('button').eq(1).click(function () { //通过$.get去发送Ajax请求 $.post('http://127.0.0.1:8000/jQuery-server',{a:100,b:200},function (data) { console.log(data); });//服务端返回的类型是对象并转为json格式,客户端如果没有加‘json’收到的是字符串而不是对象 }) </script> </div> </body> </html>
app.all('/jQuery-server',(request,response) =>{ response.setHeader('Access-Control-Allow-Origin','*'); const data = {name:'zhou'}; response.send(JSON.stringify(data)); });
get中的参数(url,数据,回调函数,返回数据的格式)
2.AJAX-JQuery通用方法发送
<script> $('button').eq(2).click(function () { //JQuery通用方法来发送请求,这个方法的名字叫ajax,属于$对象 //这个方法接收一个参数,这个参数是一个对象,对象里面有很多属性 $.ajax({ url:'http://127.0.0.1:8000/delay', data:{a:100,b:200}, type:'GET', //对响应体类型的设置,设置为json时,传回来如果是个对象的话,接收的就是对象而不是字符串 dataType:'json',//还有text纯文本选值 //成功的回调,对响应体结果做一个处理 //执行成功后调用的函数 success:function (data) { console.log(data); }, //超时时间 timeout:2000, //执行失败调用的函数 error:function () { console.log('出错了'); }, headers:{ c:300, d:400 } }) }) </script>
//延时响应 app.all('/delay',(request,response)=>{ response.setHeader('Access-Control-Allow-Origin','*'); setTimeout(()=>{ response.send('HELLO AJAX POST'); },3000); }); //jQuery服务 app.all('/jQuery-server',(request,response) =>{ response.setHeader('Access-Control-Allow-Origin','*'); const data = {name:'zhou'}; response.send(JSON.stringify(data)); });
六.axios-AJAX工具库
1.发送get请求和post请求
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script crossorigin="anonymous" src="https://cdn.bootcdn.net/ajax/libs/axios/0.26.1/axios.js"></script> </head> <body> <button>GET</button> <button>POST</button> <button>AJAX</button> <script> const btns = document.querySelectorAll('button'); //配置baseUrl axios.defaults.baseURL = 'http://127.0.0.1:8000'; btns[0].onclick = function () { //GET请求 axios.get('/axios-server',{ //url参数 params:{ id:100, name:'z' }, //请求头信息 headers:{ age:18 } //处理返回结果,结果会自动转换为对象,不需要json }).then(value =>{ console.log(value); } ); } btns[1].onclick = function () { axios.post('/axios-server',{//请求体 // data:{ username:'admin', password:'admin' },{//其他信息 //url参数 params:{ id:159 }, //请求头 headers: { name:'z' } }) } //通用发送方法AJAX请求 btns[2].onclick = function () { axios({ //请求方法 method: 'POST', url:'/axios-server', //url参数 params:{ a:100, b:200 }, //头信息 headers:{ a:100, b:100 }, //请求体参数 data:{ username: 'admin', password: 'admin' } }).then(respnse=>{ console.log(respnse); }) } </script> </body> </html>
2.使用fetch发送请求
大多都使用axios,使用fetch较少
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button>AJAX请求</button> <script> const btn = document.querySelector('button'); btn.onclick = function () { fetch('http://127.0.0.1:8000/fetch-server',{ //请求方法 method:'POST', //请求头 headers:{ name:'z' }, //请求体 body:'username=admin&password=admin' }).then(response=>{ return response.text();//如果服务端返回的数据是json,则return response.json(); }).then(response=>{ console.log(response); }); } </script> </body> </html>
编辑
七.其他
1.跨域问题
同源策略
是一种安全机制。
同源:当前网址的url和ajax请求资源的url,两者的协议、域名、端口号必须完全相同。
同源就是同一个来源。
违背同源就是跨域。
AJAX发送请求时默认是遵循同源策略的,也就是说不是同源没法直接发AJAX请求。
演示什么是同源
const express = require('express'); const app = express(); app.get('/home',(request,response)=>{ //响应一个页面 response.sendfile(__dirname+'/Ajax_26.html'); }); app.get('/data',(request,response)=>{ response.setHeader('Access-Control-Allow-Origin','*'); response.send('我是数据'); }) app.listen(9000,()=>{ console.log("服务已经启动"); });
访问home资源,返回一个页面
编辑
该页面有一个按钮,点击访问同源的data资源
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button>获取数据</button> <script> var btn = document.querySelector('button'); btn.onclick = function () { const x = new XMLHttpRequest(); //因为这里是同源的,所以url可以简写,资源都是来自于http://127.0.0.1:9000 x.open("GET",'/data'); //发送 x.send(); x.onreadystatechange = function () { if(x.readyState === 4){ if(x.status>=200&&x.status<300){ console.log(x.response); } } } } </script> </body> </html>
页面资源和数据资源是同源的
1.1如何解决跨域?
JSONP解决
编辑
编辑
CORS解决
编辑
八.案例
1.失去焦点后,验证用户名格式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="http://apps.bdimg.com/libs/bootstrap/3.3.4/css/bootstrap.min.css"> <script src="jquery-3.4.1.min.js"></script> </head> <body> <div> <div class="container"> <h2 class="page-header">JQuery发送Ajax请求</h2> <button class="btn btn-primary">GET</button> <button class="btn btn-danger ">POST</button> <button class="btn btn-info">通用</button> </div> <script> $('button').eq(0).click(function () { //通过$.get去发送Ajax请求 $.get('http://127.0.0.1:8000/jQuery-server',{a:100,b:200},function (data) { console.log(data); },'json');//响应体类型为json。 }) $('button').eq(1).click(function () { //通过$.get去发送Ajax请求 $.post('http://127.0.0.1:8000/jQuery-server',{a:100,b:200},function (data) { console.log(data); });//服务端返回的类型是对象并转为json格式,客户端如果没有加‘json’收到的是字符串而不是对象 }) $('button').eq(2).click(function () { //JQuery通用方法来发送请求,这个方法的名字叫ajax,属于$对象 //这个方法接收一个参数,这个参数是一个对象,对象里面有很多属性 $.ajax({ url:'http://127.0.0.1:8000/delay', data:{a:100,b:200}, type:'GET', //对响应体类型的设置,设置为json时,传回来如果是个对象的话,接收的就是对象而不是字符串 dataType:'json', //成功的回调,对响应体结果做一个处理 success:function (data) { console.log(data); }, //超时时间 timeout:2000, error:function () { console.log('出错了'); }, headers:{ c:300, d:400 } }) }) </script> </div> </body> </html>
//检测用户名 app.all('/check-username',(request,response)=>{ const data = { exist:1, msg:"用户名已经存在" }; let str = JSON.stringify(data); response.end(`handle(${str})`); })
编辑
\