1. XMLHttpRequest
是什么?

和axios的关系:
axios 内部采用 XMLHttpRequest 与服务器交互

学习XMLHttpRequest的目的:
掌握使用 XHR 与服务器进行数据交互,了解 axios 内部原理,加强对知识的理解,提升技术认知。
1.1. 基本语法
步骤:
- 创建 XMLHttpRequest 对象
- 配置请求方法和请求 url 地址
- 监听 loadend 事件接收响应结果
- 发起请求

javascript
// 1. 创建 XMLHttpRequest 对象
const xhr = new XMLHttpRequest()
// 2. 配置请求方法和请求 url 地址
xhr.open('请求方法','请求url网址')
// 3. 监听 loadend 事件接收响应结果
xhr.addEventListener('loadend', () => {
//响应结果
console.log(xhr.response)
})
// 4. 发起请求
xhr.send()
1.1.1. 获取省份案例
需求:获取并展示所有省份名字

html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="data"></div>
<script>
// 1. 实例化XHR对象
const xhr = new XMLHttpRequest()
// 2. open方法设置请求方法和url路径
xhr.open('GET','https://hmajax.itheima.net/api/province')
// 3. 设定接收服务器的响应事件 loadend
// loadend是XMLHttpRequest的一个事件,当服务器响应了不论是否成功都触发这个事件
xhr.addEventListener('loadend',function(){
// 获取服务器响应的结果(响应体的数据 xhr.response是一个字符串(JSON) )
console.log(xhr.response)
// 如何判断是成功还是失败的响应: xhr.status >=200 && xhr.status<300
// console.log(xhr.status)
if(xhr.status >=200 && xhr.status<300){
// 成功
let jsObj = JSON.parse(xhr.response)
console.log(jsObj);
// 其他的逻辑写在这里。。。。
document.querySelector('.data').innerHTML = jsObj.list.join('<br>')
}else{
// 失败
}
})
// 4. send()发送请求
xhr.send()
</script>
</body>
</html>
1.2. 查询参数
**定义:**浏览器提供给服务器的额外信息,让服务器返回浏览器想要的数据
语法: XXXX参数名1=值1 & 参数名2=值2
多个参数之间 用 & 符号分隔的键/值对列表

如何使用XMLHttpRequest发送携带参数的请求?

javascript
// 1. 创建 XMLHttpRequest 对象
const xhr = new XMLHttpRequest()
// 2. 配置请求方法和请求 url 地址
xhr.open('请求方法','请求url网址?key1=value1&key2=value2&.....')
// 3. 监听 loadend 事件接收响应结果
xhr.addEventListener('loadend', () => {
//响应结果
console.log(xhr.response)
})
// 4. 发起请求
xhr.send()
1.2.1. 查询地区
需求:输入【省份】和【城市】名字点击查询按钮,获得地区列表

开发步骤:

html
<!DOCTYPE html>
<html lang="zh-CN">
<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>案例_地区查询</title>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet">
<style>
:root {
font-size: 15px;
}
body {
padding-top: 15px;
}
</style>
</head>
<body>
<div class="container">
<form id="editForm" class="row">
<!-- 输入省份名字 -->
<div class="mb-3 col">
<label class="form-label">省份名字</label>
<input type="text" value="广东省" name="province" class="form-control province" placeholder="请输入省份名称" />
</div>
<!-- 输入城市名字 -->
<div class="mb-3 col">
<label class="form-label">城市名字</label>
<input type="text" value="深圳市" name="city" class="form-control city" placeholder="请输入城市名称" />
</div>
</form>
<button type="button" class="btn btn-primary sel-btn">查询</button>
<br><br>
<p>地区列表: </p>
<ul class="list-group area-group">
<!-- 示例地区 -->
<li class="list-group-item">东城区</li>
</ul>
</div>
<script>
document.querySelector('button').addEventListener('click', function () {
let pname = document.querySelector('.form-control.province').value
let cname = document.querySelector('.form-control.city').value
const xhr = new XMLHttpRequest()
// ✨✨✨带参数请求的核心代码就是在url后面使用?key=value&key1=value1传参
xhr.open('GET', `https://hmajax.itheima.net/api/area?pname=${pname}&cname=${cname}`)
xhr.addEventListener('loadend', function () {
if (xhr.status >= 200 && xhr.status < 300) {
// ✨✨✨将xhr.response 这个json字符串转成对象
let jsObj = JSON.parse(xhr.response)
console.log(jsObj);
let str = ''
jsObj.list.forEach(item => {
str += `<li class="list-group-item">${item}</li>`
})
document.querySelector('.list-group').innerHTML = str
}
})
xhr.send()
})
</script>
</body>
</html>
1.3. 提交数据(POST)
**场景:**将页面表单数据提交给服务器,例如:登录,注册,密码修改,新增,编辑等业务
XMLHttpRequest数据提交核心步骤:
- 请求头设置Content-Type
- 请求体携带符合要求的数据
举例:如下注册账号接口

- 请求头设置Content-Type: application/json
- 请求体携带 JSON 字符串
核心代码:

html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="./lib/axios.js"></script>
<script>
// axios({
// url:'https://hmajax.itheima.net/api/register',
// method:'POST',
// data:{
// username:'itheima524',
// password:'12345678'
// }
// })
// .then(res=>{
// console.log(res.data)
// })
const xhr = new XMLHttpRequest()
xhr.open('POST','https://hmajax.itheima.net/api/register')
xhr.addEventListener('loadend',function(){
if(xhr.status>=200 && xhr.status <300){
console.log(xhr.response)
}
})
// 在发送之前增加请求报文头Content-Type
xhr.setRequestHeader('Content-Type','application/json')
// xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
// 准备请求体数据
let userInfo = {username:'itheima536',password:'12345678'}
//✨✨ 注意点:由于Contet-type是一个application/json,所以必须将对象转换成json字符串发送
let userInfoBody = JSON.stringify(userInfo)
// ✨✨ send()里面如果带了参数,表示向请求报文体中增加数据发送给服务器
// get请求是无需带参数的,只有POST,PUT,PATCH这些方法才带参数
xhr.send(userInfoBody)
// xhr.send('username=itheima536&password=12345678')
</script>
</body>
</html>
1.4. 文件上传
- 实例化FormData
- 使用append方法根据接口文档添加参数
- send方法发送formdata对象

html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="file" class="img">
<script>
document.querySelector('.img').addEventListener('change',function(){
// 1. 获取选择的图片
let file = this.files[0]
// 2. 实例化FormData对象
const fd = new FormData()
fd.append('img',file)
const xhr = new XMLHttpRequest()
xhr.open('POST','https://hmajax.itheima.net/api/uploadimg')
xhr.addEventListener('loadend',function(){
if(xhr.status >=200 && xhr.status<300){
console.log(xhr.response)
}else{
alert('失败')
}
})
// 3. 将formData对象提交给服务器
xhr.send(fd)
})
</script>
</body>
</html>
1.5. XHR总结
XHR是什么? 浏览器提供的一个和服务器通讯的对象(XMLHttpReqeust)
和axios的关系是什么?axios库里面针对XHR来进行封装的
面试官:请手写一个和服务器通讯的ajax代码,不允许使用axios
核心步骤:
- 创建对象 :
var xhr = new XMLHttpRequest();
- 配置请求 :
xhr.open('GET', 'URL');
- 处理响应:
-
- 设置状态改变时的回调函数:
xhr.addEventListener('loadend',function(){})
- 检查
xhr.status >= 200 && xhr.status < 300
确认成功。
- 设置状态改变时的回调函数:
- 发送请求 :
xhr.send();
- GET请求核心要素
-
- 修改open方法第一个参数为GET,第二个参数表示请求的url地址
-
-
- URL地址如果需要带参数-> ?key=value&key1=value1
-
- POST请求的核心要素
-
- 在发送请求之前使用
xhr.setReqeustHeader()
设置Contnet-Type请求头
- 在发送请求之前使用
-
-
- applicaton/json -> json字符串
- application/x-www-form-urlencoded -> key=value&key1=value1
-
-
- 在send方法中传入符合Content-type格式要求的数据
- 文件上传的核心要素
-
- 配合<input type="file">这个元素来实现的
- 实例化FormData 以及使用append方法追加数据
- send()方法将formdata对象发生给服务器
- 注意点:文件上传不需要手动设置Contnet-Type
2. Promise + XHR 实现myAxios获取省份列表
目标:通过 Promise+XHR模拟axios函数的封装,体验axios内部的实现过程
需求:
- 使用 Promise 管理 XHR ,模拟实现一个简单版的myAxios
- 使用myAxios访问:http://hmajax.itheima.net/api/province 获取省份数据
实现步骤:
- 创建myAxios函数,内部使用返回一个 new Promise((resolve,reject)=>{ })
- 执行 XHR 异步代码,获取省份列表 接口文档
- 请求成功(
xhr.status >= 200 && xhr.status < 300
)或失败函数,做后续处理
-
- resolve(成功的数据)
- reject(失败数据)
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- <script src="./lib/axios.js"></script> -->
<script>
/* myAxios()
.then()
.catch()
拆解:
1. 构造出 能 .then().catch()
2. 在Promise中通过XHR去和服务器通信
3. 服务器响应的成功或者失败结果,由Promise中的resolve和reject交出去
*/
function myAxios() {
return new Promise((resolve, reject) => {
// resolve(100)
// // reject('错误:100')
// 借助XHR来发送请求和响应
const xhr = new XMLHttpRequest()
xhr.open('GET','https://hmajax.itheima.net/api/city?pname=广东省')
xhr.addEventListener('loadend',function(){
if(xhr.status >=200 && xhr.status <300){
// 成功
resolve(xhr.response)
}else{
reject('失败')
}
})
xhr.send()
})
}
myAxios()
.then(res=>{
console.log(res);
})
.catch(err=>{
console.log(err);
})
// async function call() {
// try {
// let res = await myAxios()
// console.log(res);
// } catch (err) {
// console.log(err);
// }
// }
// call()
</script>
</body>
</html>
