️️一篇快速上手 AJAX 异步前后端交互
AJAX
- 1. AJAX
- 1.1 AJAX 简介
- 1.2 AJAX 优缺点
- 1.3 AJAX 前后端准备
- 1.4 AJAX 请求基本操作
- 1.5 AJAX 发送 POST 请求
- 1.6 设置请求头
- 1.7 响应 JSON 数据
- 1.8 AJAX 请求超时与网络异常处理
- 1.9 取消请求
- 1.10 Fetch 发送 Ajax 请求
- 2. jQuery-Ajax
- 2.1 jQuery 发送 Ajax 请求(GET和POST)
- 2.2 jQuery 通用方法发送 Ajax 请求
- 3. Axios-Ajax
- 3.1 Axios 发送 Ajax 请求(GET和POST)
- 3.2 Axios 函数发送 Ajax 请求
- 4. 跨域
- 4.1 同源策略
- 4.2 如何解决跨域
- 4.2.1 JSONP
- 4.2.2 CORS
1. AJAX
1.1 AJAX 简介
AJAX 全名 Asynchronous Javascript and XML(异步 JavaScript 和 XML)
-
AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。
-
通过 AJAX 可以在浏览器中向服务器发送异步请求,可以实现 无刷新获取数据。
应用场景:
1.2 AJAX 优缺点
✅ 可以无需刷新页面而与服务器端进行通信。
✅ 允许你根据用户事件(鼠标事件、键盘事件、表单事件…)来更新部分页面内容。
❎ 没有浏览历史,不能回退。
❎ 存在跨域问题
❎ SEO 不友好,AJAX的内容是动态创建到页面当中去,不好爬取代码。
1.3 AJAX 前后端准备
使用 nodejs 作为服务端,与 html 页面交互
GET.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AJAX GET 请求</title>
<style>
#result{
width: 200px;
height: 100px;
border: solid 1px red;
}
</style>
</head>
<body>
<button>点击发送请求</button>
<div id="result"></div>
</body>
</html>
server.js
const express = require("express");
const app = express();
// 路由规则
app.get("/server", (request, response) => {
// 设置响应头,允许跨域
response.setHeader("Access-Controll-Allow-Origin", "*");
// 设置响应体
response.send("Hello AJAX");
});
// 监听端口,启动服务
app.listen(8000, () => {
console.log("服务已启动...");
});
1.4 AJAX 请求基本操作
点击按钮向服务端发送 AJAX 请求,响应结果到 div 中
发送 AJAX 请求操作:
<script>
const btn = document.getElementsByTagName("button")[0];
btn.onclick = function () {
// 1.创建对象
const xhr = new XMLHttpRequest();
// 2.初始化, 设置请求方法和url
xhr.open("GET", "http://127.0.0.1:8000/server");
// 3.发送
xhr.send();
// 4.事件绑定 处理服务端返回的结果
// readyState: 0-未初始化 1-open方法调用完毕 2-send方法调用完毕 3-服务端返回了部分结果 4-服务端返回了所有结果
xhr.onreadystatechange = function () {
// 判断服务端是否返回了所有结果
if (xhr.readyState === 4) {
// 判断是否响应成功 2xx
if (xhr.status >= 200 && xhr.status < 300) {
console.log(xhr.status); // 状态码
console.log(xhr.statusText); // 状态字符串
console.log(xhr.getAllResponseHeaders()); // 所有响应头
console.log(xhr.response); // 响应体
} else {
}
}
};
};
</script>
AJAX 请求成功
返回响应结果到页面中
<script>
const btn = document.getElementsByTagName("button")[0];
const result = document.getElementById("result");
btn.onclick = function () {
// 1.创建对象
const xhr = new XMLHttpRequest();
// 2.初始化, 设置请求方法和url
xhr.open("GET", "http://127.0.0.1:8000/server");
// 3.发送
xhr.send();
// 4.事件绑定 处理服务端返回的结果
// readyState: 0-未初始化 1-open方法调用完毕 2-send方法调用完毕 3-服务端返回了部分结果 4-服务端返回了所有结果
xhr.onreadystatechange = function () {
// 判断服务端是否返回了所有结果
if (xhr.readyState === 4) {
// 判断是否响应成功 2xx
if (xhr.status >= 200 && xhr.status < 300) {
result.innerHTML = xhr.response;
} else {
}
}
};
};
</script>
1.5 AJAX 发送 POST 请求
鼠标移入 div 时向服务端发请求,然后把响应体结果放入 div 中呈现
AJAX 发送 POST 请求
const result = document.getElementById("result");
result.addEventListener("mouseover", function () {
const xhr = new XMLHttpRequest();
xhr.open("POST", "http://127.0.0.1:8000/server");
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
result.innerHTML = xhr.response;
}
}
};
});
nodejs 添加对应的路由规则
app.post("/server", (request, response) => {
// 设置响应头,允许跨域
response.setHeader("Access-Control-Allow-Origin", "*");
// 设置响应体
response.send("Hello AJAX POST");
});
附带请求参数
xhr.send("a=199&b=1");
1.6 设置请求头
由于使用了自定义头,浏览器安全机制会阻止发送请求
在 nodejs 中设置放行所有头信息
放行之后仍然不行,因为还会发送一个 OPTIONS 的请求做一个头信息校验,这时没有匹配的路由规则所以无法成功。
路由规则设置为 all 可以接受任意类型的请求即可
1.7 响应 JSON 数据
nodejs:
app.all("/json-server", (request, response) => {
// 设置响应头,允许跨域
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Headers", "*");
const data = {
name: "Fetters"
};
let str = JSON.stringify(data)
// 设置响应体
response.send(str);
});
1️⃣ 手动数据转换
const result = document.getElementById("result");
result.addEventListener("mouseover", function () {
const xhr = new XMLHttpRequest();
xhr.open("POST", "http://127.0.0.1:8000/json-server");
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
// 手动对数据转换
let data = JSON.parse(xhr.response);
result.innerHTML = data;
}
}
};
});
2️⃣ 设置响应体类型自动转换
const result = document.getElementById("result");
result.addEventListener("mouseover", function () {
const xhr = new XMLHttpRequest();
// 设置响应体数据的类型
xhr.responseType = "json";
xhr.open("POST", "http://127.0.0.1:8000/json-server");
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
result.innerHTML = xhr.response.name;
}
}
};
});
1.8 AJAX 请求超时与网络异常处理
nodejs:
app.get("/delay", (request, response) => {
response.setHeader("Access-Control-Allow-Origin", "*");
setTimeout(() => {
response.send("延时响应");
}, 3000);
});
html:
<body>
<button>点击发送请求</button>
<div id="result"></div>
<script>
const btn = document.getElementsByTagName("button")[0];
const result = document.getElementById("result");
btn.addEventListener("click", 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>
请求超时:
网络异常:
1.9 取消请求
html:
<body>
<button>点击发送请求</button>
<button>点击取消请求</button>
<script>
const btns = document.querySelectorAll("button");
let xhr = null;
btns[0].onclick = function () {
xhr = new XMLHttpRequest();
xhr.open("GET", "http://127.0.0.1:8000/delay");
xhr.send();
};
// abort
btns[1].onclick = function () {
xhr.abort();
};
</script>
</body>
1.10 Fetch 发送 Ajax 请求
btn.onclick = function () {
fetch("http://127.0.0.1:8000/fetch-server?vip=10", {
// 请求方法
method: "POST",
// 请求头
headers: {
name: "Fetters",
},
// 请求体
body: "username=admin&password=admin",
}).then(response => {
return response.text();
}).then(data => {
console.log(data);
});
};
2. jQuery-Ajax
2.1 jQuery 发送 Ajax 请求(GET和POST)
// GET
$('button').eq(0).click(function() {
$.get('http://127.0.0.1:8000/jquery-server', {a:100, b:200}, function(data) {
console.log(data);
}, 'json');
});
// POST
$('button').eq(0).click(function() {
$.post('http://127.0.0.1:8000/jquery-server', {a:100, b:200}, function(data) {
console.log(data);
});
});
2.2 jQuery 通用方法发送 Ajax 请求
$('button').eq(2).click(function() {
$.ajax({
// url
url: 'http://127.0.0.1:8000/jquery-server',
// 参数
data: {a: 100, b:200},
// 请求类型
type: 'GET',
// 响应体结果
dataType: 'json',
// 成功的回调
success: function(data) {
console.log(data);
},
// 超时时间
timeout: 2000,
// 失败的回调
error: function() {
console.log('error!');
},
// 头信息
headers: {
c: 300,
d: 400
}
});
});
3. Axios-Ajax
3.1 Axios 发送 Ajax 请求(GET和POST)
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,
vip: 7,
},
// 请求头参数
headers: {
name: "Fetters",
age: 23,
},
}).then(value => console.log(value));
};
btns[1].onclick = function () {
// POST
axios.post("/axios-server",
// 请求体
{
username: "admin",
password: "admin",
},
{
// url 参数
params: {
id: 100,
vip: 7,
},
// 请求头参数
headers: {
name: "Fetters",
age: 23,
},
}
).then(value => console.log(value));
};
3.2 Axios 函数发送 Ajax 请求
btns[2].onclick = function () {
axios({
// 请求方法
method: "POST",
// url
url: "/axios-server",
// url 参数
params: {
vip: 10,
level: 20,
},
// 头信息
headers: {
a: 100,
b: 200,
},
// 请求体参数
data: {
username: "admin",
password: "admin",
},
}).then(response => {
console.log(response);
});
};
4. 跨域
4.1 同源策略
同源策略(Same-Origin Policy)最早由 Netscape 公司提出,是浏览器的一种安全策略。
同源:协议、域名、端口号 必须完全相同
违背同源策略就是跨域
4.2 如何解决跨域
4.2.1 JSONP
-
JSONP是什么
JSONP (JSON with Padding),是一个非官方的跨域解决方案,纯粹凭借程序员的聪明才智开发出来,只支持 get 请求
-
JSONP 怎么工作的?
在网页有一些标签天生具有跨域能力,比如:img, link, iframe, script。
JSONP就是利用 script 标签的跨域能力来发送请求的。
-
JSONP的使用
-
获取客户端发送过来的回调函数的名字
-
得到要通过JSONP形式发送给客户端的数据
-
根据前两步得到的数据,拼接出一一个函数调用的字符串
-
把上一步拼接得到的字符串,响应给客户端的``标签进行解析执行
🎗️ node服务器端代码
const express = require('express') const app = express() const port = 3000 //路由配置 app.get("/user",(req,res)=>{ //1.获取客户端发送过来的回调函数的名字 let fnName = req.query.callback; //2.得到要通过JSONP形式发送给客户端的数据 const data = {name:'tom'} //3.根据前两步得到的数据,拼接出个函数调用的字符串 let result = `${fnName}({name:"tom"})` //4.把上步拼接得到的字符串,响应给客户端的<script> 标签进行解析执行 res.send(result); }) app.listen(port, () => { console.log(`Example app listening on port ${port}`) })
🎗️ 前端代码
<head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JSONP简单实现</title> </head> <body> <button id="btn">点击发送请求</button> <script> function getJsonpData(data) { console.log("获取数据成功") console.log(data) //{name:'tom'} } var btn = document.getElementById("btn"); btn.onclick = function () { //创建script标签 var script = document.createElement("script"); script.src = 'http://localhost:3000/user?callback=getJsonpData'; document.body.appendChild(script); script.onload = function () { document.body.removeChild(script) } } </script> </body> </html>
-
4.2.2 CORS
推荐文章
- http://www.ruanyifeng.com/blog/2016/04/cors.html
- https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
-
CORS (Cross-Origin Resource Sharing), 跨域资源共享。CORS 是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持 get 和 post 等请求。跨域资源共享标准新增了一组 HTTP 首部字段(响应头),允许服务器声明哪些源站通过浏览器有权限访问哪些资源
-
CORS怎么工作的?
CORS 是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行
-
CORS 的使用
// 设置响应头,允许跨域 response.setHeader("Access-Control-Allow-Origin", "*");