先来一个经典的手写原生AJAX
let xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
console.log(xhr.response);
} else {
console.log('请求失败');
}
}
}
xhr.open('get', 'http://localhost:3000/xuesheng')
xhr.send()
1、什么是AJAX
AJAX 全称为 Asynchronous JavaScript And XML,就是异步的 JS 和 XML。 通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。 AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。
2、AJAX的特点
2.1 优点
- 可以无需刷新页面而与服务器端进行通信。
- 允许你根据用户事件来更新部分页面内容。
2.2 缺点
- 没有浏览历史,不能回退
- 存在跨域问题(同源)
- SEO 不友好
3、AJAX的使用
3.1 核心对象
3.2 readyState
xhr对象有一个readyState属性,表示当前处在请求/相应过程的哪个阶段,这个属性有以下值:
- 0 未初始化 尚未调用open()方法
- 1 已打开 已调用open()方法,尚未调用send()方法
- 2 已发送 已调用send()方法,尚未收到响应
- 3 接受中 已经收到部分响应
- 4 完成 已经收到所有响应,这里不分失败还是成功,所以需要在判断status值
每次readyState从一个值变成另一个值都会触发readystatechange事件。
在收到响应之前如果想取消异步请求,可以调用abort()方法
xhr.abort() 调用这个方法后,XHR对象会停止触发事件,并阻止访问这个对象上任何与响应相关的属性。
3.3 GET请求
<body>
<button id="btn">获取</button>
</body>
<script>
const btn = document.getElementById('btn')
btn.addEventListener('click', function () {
let xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
console.log(xhr.responseText);
} else {
console.log('请求失败');
}
}
}
xhr.open('get', 'http://localhost:3000/xuesheng')
xhr.send()
})
</script>
当携带参数时,因为get请求没有请求体,数据都是放置于URL后的
形如:key=value&key=value 就是query参数的urlencoded编码形式
形如:/xx/xxx/帅比/20 就是params参数需要在后端路由占位的
//携带query参数
xhr.open('GET','http://localhost:3000/xuesheng?name=帅比&age=20')
//携带params参数
xhr.open('GET','http://localhost:3000/xuesheng/帅比/20')
3.4. POST请求
post与get方法不同的点在于,post发送的数据可以用params、query或者请求体,一般使用请求体,并且需要设置请求体编码形式相应的请求头。
<body>
<button id="btn">获取</button>
</body>
<script>
const btn = document.getElementById('btn')
btn.addEventListener('click', function () {
let xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
console.log(xhr.responseText);
} else {
console.log('请求失败');
}
}
}
xhr.open('post', 'http://localhost:3000/xuesheng')
//这里请求体是urlencoded编码格式,这里就要设置好这个请求头
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
xhr.send('name=帅比&age=20')
//这里请求体是json编码格式
xhr.setRequestHeader('Content-type', 'application/json')
const person = { name: '帅比', age: 20 }
xhr.send(JSON.stringify(person)) //携带json编码形式的请求体参数
})
</script>
JSON.stringify()方法将()里的 JavaScript 对象或值转换为 JSON 字符串
JSON.parse()方法用来解析()里的 JSON 字符串,构造由字符串描述的 JavaScript 值或对象
3.5 解决多次重复请求
这种方法可以用在很多地方解决一些重复发请求的问题,也叫防抖
<body>
<button id="btn">获取</button>
</body>
<script>
const btn = document.getElementById('btn')
let xhr
let isLoading //
btn.addEventListener('click', function () {
if(isLoading) xhr.abort() //
xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
isLoading = false //
console.log(xhr.responseText);
} else {
console.log('请求失败');
}
}
}
xhr.open('get', 'http://localhost:3000/xuesheng')
xhr.send()
isLoading = true //
})
</script>
4、跨域问题
4.1 为什么会有跨域问题
浏览器为了安全,而采用的同源策略
4.2 什么是同源策略
- 同源策略是由Netscape提出的一个著名的安全策略,现在所有支持JavaScript的浏览器都会使用这个策略
- web是构建再同源策略基础上的,浏览器只是针对同源策略的一种实现
- 所谓同源是指:协议、域名(IP)、端口必须要完全相同
即:协议、域名(IP)、端口都相同,才能算是在同一个域里
4.3 非同源受到哪些限制?
-
Cookie不能读取
-
DOM无法获得
-
Ajax请求可以发,但是获取不到数据
4.4 jsonp避免跨域
要明确的是:jsonp不是一种技术,而是程序员"智慧的结晶"(利用了标签请求资源不受同源策略限制的特点)
jsonp原理:绕开xhr利用标签请求资源不受同源策略限制的特点,通过动态创建<script>元素并为src属性指定跨域URL实现,传输数据,也只能发get请求。需要前后端配合,前端定义函数,后端调函数传参数,并把传的参数转为json格式。
//前端代码
<body>
<button id="btn">jsonp获取数据</button>
</body>
<script>
const btn = document.getElementById('btn')
btn.addEventListener('click', function () {
//1、创建script节点
const scriptNode = document.createElement('script')
//2、给节点指定src属性
scriptNode.src = 'http://localhost:3000/xuesheng'
//3、将节点放入页面
document.body.appendChild(scriptNode)
//4、准备好一个函数
window.lyc = function(a){
console.log(a);
}
//5、移除已经使用过的script节点
document.body.removeChild(scriptNode)
})
</script>
//后端处理
app.get('/xuesheng', (request, response) => {
const { callback } = request.query
const person = [{ name: '帅比', age: 20 }, { name: '小帅比', age: 22 }]
response.send(`${callback}(${JSON.stringify(person)})`)
})
4.5 jsonp面试题
json和jsonp有关系吗?
json是一种存储和交互数据的格式
jsonp是一种解决跨域的方法(其实是避免跨域)
有关系是,当使用jsonp时 后端调用前面函数时,传的参数必须转为json字符串
jsonp解决跨域有用到xhr吗?
不对,根本没用到
jsonp解决跨域有什么缺点?
需要前后端配合
4.6 CORS解决跨域
无需前端人员做任何操作
安装 npm add cors
引入 const cors = require(‘cors’)
使用 app.use(cors())