AJAX简介
在js中向服务器发送请求加载数据的技术叫AJAX
AJAX:
- A -- async(异步) J -- JAVASCRIPT A -- AND X -- XML
- 异步的JS和XML
- 作用是通过JS向服务器发送请求来加载数据
- xml是早期AJAX使用的数据格式
<student>
<name>Megumi</name>
</student>
- 目前使用的格式都使用JSON(简单、体积小、易懂)
{"name": "megumi"} - 可以选择的通信方案
- XMLHTTPRequest(xhr)
- Fetch
- Axios (二次封装)
跨域的原因和解决办法
CORS(跨域资源共享):
- 跨域请求:
两个网站的完整域名不相同:比如a网站是haha.com b网站是heihei.com 那么就是跨域 跨域需要检查三个东西:协议、域名、端口号,只要有一个不同即算跨域,当我们通过AJAX去发送跨域请求时,浏览器为了服务器的安全,会阻止JS读取到服务器的数据 - 解决方案:在服务器中设置一个允许跨域的头即可
Access-Control-Allow-Origin允许客户端访问我们的服务器(详细可见下文)
XHR使用(技术很古老,一般了解即可)
前端部分:
<!DOCTYPE html>
<html lang="en">
<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>Xhr</title>
</head>
<body>
<h1>AJAX测试</h1>
<hr>
<button id="btn">
点我加载数据
</button>
<div class="root"></div>
<script>
const btn = document.querySelector("#btn")
btn.onclick = ()=>{
// 创建一个xhr对象
const xhr = new XMLHttpRequest()
const root = document.querySelector(".root")
// 设置响应体类型,自动转化
xhr.responseType = "json"
// 设置请求信息
xhr.open("get","http://localhost:3000/students")
// 发送请求
xhr.send()
// 读取响应信息
// console.log(xhr.response) //异步代码不能同步加载
// 放在加载完之后响应即可()
xhr.onload = ()=> {
//xhr表示响应状态码
if(xhr.status === 200) {
// console.log(xhr.response)
const result = xhr.response
// console.log(result)
if(result.status === 'ok'){
// 创建ul
const ul = document.createElement("ul")
// 将ul插入到root中
root.appendChild(ul)
// 遍历数组
for (let stu of result.data) {
ul.insertAdjacentHTML(
"beforeend",
`<li>${stu.name}--${stu.age}--${stu.gender}--${stu.add}</li>`
)
}
}
}
}
}
</script>
</body>
</html>
express编写的node服务
const express = require("express")
const app = express()
const STUDENT_ARR=[{
id:'1',name:'megumi',age:18,add:'heart',gender:'♀'
},{
id:'2',name:'kurumi',age:18,add:'heart',gender:'♀'
}]
// 配置允许跨域的中间件
app.use((req,res,next)=>{
res.setHeader("Access-Control-Allow-Origin","*")
})
app.get("/students",(req,res)=>{
console.log("student收到了get请求")
res.send({
status: 'ok',
data:STUDENT_ARR
})
})
app.listen(3000,()=>{
console.log("Explosion!!")
})
Fetch(浏览器的内置请求函数 只存在浏览器环境中)
fetch是xhr的升级版,采用的是Promise异步API 使用起来更加友好 fetch元素js只支持这种ajax请求的方法
前端部分
<!DOCTYPE html>
<html lang="en">
<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>Document</title>
</head>
<body>
<h1>AJAX测试</h1>
<hr>
<button id="btn">
点我加载数据
</button>
<br>
<button id="btn2">
点我加载数据2
</button>
<div class="root"></div>
<script>
const btn = document.querySelector("#btn")
const btn2 = document.querySelector("#btn2")
btn.onclick = ()=>{
fetch("http://localhost:3000/students")
.then(res=>{
if(res.status === 200){
// reurn 出来的是promise还需要去then一下获取数据
return res.json()
} else {
throw new Error("加载失败")
}
})
.then(res=>{
console.log(res)
})
.catch((err)=>{
console.log("出错辣",err)
})
}
btn2.onclick = ()=>{
fetch("http://localhost:3000/students",{
method: 'POST',
headers: {
"Content-type": "application/json"
},
// 通过 body 去发送数据时,必须通过请求头来指定数据的类型
body: JSON.stringify({
name:"megumi",
age: 18,
gender: '♀',
address: "heart"
})
})
}
</script>
</body>
</html>
我们只需要在上面的代码添加students的路由即可
// 定义添加学生的路由
app.post("/students",(req,res)=>{
// 获取学生的信息
// 一般会有校验但这里就不校验辣
const { name,age,add,gender } = req.body
// 将学生的信息添加到数组中
console.log("students受到post请求")
const stu = {
id: +STUDENT_ARR.at(-1).id + 1 + '',
name,
age:+age,
add,
gender
}
STUDENT_ARR.push(stu)
res.send({
status:'ok',
data:stu
})
})
Axios(常用)
axios是二次封装的XHR增加了一些扩展性 (后续会介绍常用的项目中的二次封装和Axios的源码解析)
axios中文文档
演示效果
<!DOCTYPE html>
<html lang="en">
<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>Axios</title>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<button id="btn">点击</button>
<script>
document.querySelector("#btn").onclick=()=>{
// 直接调用
axios({
method:'POST',
url:"http://localhost:3000/students",
data: {
name:'megami',
age:18,
gender:"♀"
}
})
.then(result=>{
// axios 默认只会在响应状态为2xx时才会调用then
// result 是axios封装过
console.log(result.data)
})
.catch(err=>{
console.log("出错辣",err)
})
}
</script>
</body>
</html>
axios的配置
<!DOCTYPE html>
<html lang="en">
<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>Axios</title>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<button id="btn">点击</button>
<script>
document.querySelector("#btn").onclick=()=>{
// 直接调用
axios({
// 请求方法,默认是get
method:'POST',
// baseURL 指定服务器的根目录(路径的前缀)
baseURL:'http://localhost:3000',
// 请求地址
url:"students",
// 指定请求头
headers: {"Content-type":"application/json"},
// 请求头
data: {
name:'megami',
age:18,
gender:"♀"
},
// params 用来指定路径中的查询字符串
params:{
id:1,
name:'xxx'
},
// timeout 过期时间
timeout:10000,
// signal 用来种终止请求
// signal:AbortController,
// transformRequest 可以用来处理请求数据(data)
// 需要数组作为参数,数组可以接收多个函数,请求发送时多个函数会按照顺序执行
// 函数在执行时,会接收到两个参数data和headers
transformRequest:[(data,headers)=>{
// 在函数中对data和headers进行修改
data.name = "xxx"
headers['Content-Type'] = "application/json"
return data
},(data,headers)=>{
// 最后一个函数必须返回一个字符串,才能使得数据有效
console.log(222)
return JSON.stringify(data)
}]
})
.then(result=>{
// axios 默认只会在响应状态为2xx时才会调用then
// result 是axios封装过
console.log(result.data)
})
.catch(err=>{
console.log("出错辣",err)
})
}
</script>
</body>
</html>
axios的默认配置
<!DOCTYPE html>
<html lang="en">
<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>Axios</title>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<button id="btn">点击</button>
<script>
axios.defaults.baseURL = "http://localhost:3000"
axios.defaults.headers.common["Authorization"] = "xxx"
document.querySelector("#btn").onclick=()=>{
// 直接调用
axios({
// 请求方法,默认是get
method:'POST',
// baseURL 指定服务器的根目录(路径的前缀)
baseURL:'http://localhost:3000',
// 请求地址
url:"students",
// 指定请求头
headers: {"Content-type":"application/json"},
// 请求头
data: {
name:'megami',
age:18,
gender:"♀"
},
params:{
id:1,
name:'xxx'
},
timeout:10000,
transformRequest:[(data,headers)=>{
data.name = "xxx"
headers['Content-Type'] = "application/json"
return data
},(data,headers)=>{
// 最后一个函数必须返回一个字符串,才能使得数据有效
console.log(222)
return JSON.stringify(data)
}]
})
.then(result=>{
// axios 默认只会在响应状态为2xx时才会调用then
// result 是axios封装过
console.log(result.data)
})
.catch(err=>{
console.log("出错辣",err)
})
}
</script>
</body>
</html>
axios的实例
<!DOCTYPE html>
<html lang="en">
<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>Axios</title>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<button id="btn">点击</button>
<script>
axios.defaults.baseURL = "http://localhost:3000"
axios.defaults.headers.common["Authorization"] = "xxx"
// axios 实例相当于axios的一个副本,它的功能和axios一样
// axios的默认配置在实例也同样会生效
// 但是我们可以单独修改axios实例的默认配置
// const instance = axios.create({
// baseURL: 'http://localhost:4000'
// })
const instance = axios.create()
instance.defaults.baseURL = 'http://localhost:4000'
document.querySelector("#btn").onclick=()=>{
// 直接调用
axios({
// 请求方法,默认是get
method:'POST',
// baseURL 指定服务器的根目录(路径的前缀)
baseURL:'http://localhost:3000',
// 请求地址
url:"students",
// 指定请求头
headers: {"Content-type":"application/json"},
// 请求头
data: {
name:'megami',
age:18,
gender:"♀"
},
params:{
id:1,
name:'xxx'
},
timeout:10000,
transformRequest:[(data,headers)=>{
data.name = "xxx"
headers['Content-Type'] = "application/json"
return data
},(data,headers)=>{
// 最后一个函数必须返回一个字符串,才能使得数据有效
console.log(222)
return JSON.stringify(data)
}]
})
.then(result=>{
// axios 默认只会在响应状态为2xx时才会调用then
// result 是axios封装过
console.log(result.data)
})
.catch(err=>{
console.log("出错辣",err)
})
}
</script>
</body>
</html>
axios拦截器
<!DOCTYPE html>
<html lang="en">
<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>Axios</title>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<button id="btn">点击</button>
<script>
axios.defaults.baseURL = "http://localhost:3000"
// axios的拦截器可以对请求或响应进行拦截,在请求发送前和响应读取前处理数据
// 拦截器只对当前的实例有效
// 添加请求拦截器
axios.interceptors.request.use(
function (config) {
// config 表示axios的配置对象
// console.log()
// config.data.name = '啧啧啧'
// 可以对请求做一些配置
return config
},
function (error) {
return Promise.reject(error)
}
)
document.querySelector("#btn").onclick=()=>{
// 直接调用
axios({
method:'POST',
url:"students",
// 请求头
data: {
name:'megami',
age:18,
gender:"♀"
},
params:{
id:1,
name:'xxx'
},
timeout:10000,
transformRequest:[(data,headers)=>{
data.name = "xxx"
headers['Content-Type'] = "application/json"
return data
},(data,headers)=>{
// 最后一个函数必须返回一个字符串,才能使得数据有效
console.log(222)
return JSON.stringify(data)
}]
})
.then(result=>{
// axios 默认只会在响应状态为2xx时才会调用then
// result 是axios封装过
console.log(result.data)
})
.catch(err=>{
console.log("出错辣",err)
})
}
</script>
</body>
</html>