AJAX
- 使用浏览器的 XMLHttpRequest 对象 与服务器通信
- 浏览器网页中,使用 AJAX技术(XHR对象)发起获取省份列表数据的请求,服务器代码响应准备好的省份列表数据给前端,前端拿到数据数组以后,展示到网页
这里使用一个第三方库叫 axios, 后续在学习 XMLHttpRequest 对象了解 AJAX 底层原理.因为 axios 库语法简单,让我们有更多精力关注在与服务器通信上,而且后续 Vue,React 学习中,也使用 axios 库与服务器通信
基本语法
url:目标资源地址,method:请求方法,params:查询参数,data:提交的数据. 请求方法:GET,POST,PUT,DELETE,PATCH
无参GET请求
1 2 3 4 5 6 7 8
| <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> axios({ url: '目标资源地址' }).then((result) => { }) </script>
|
有参GEt请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> document.querySelector('.sel-btn').addEventListener('click', () => { let pname = document.querySelector('.province').value let cname = document.querySelector('.city').value axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname, cname } }).then(result => { let list = result.data.list console.log(list) let theLi = list.map(areaName => `<li class="list-group-item">${areaName}</li>`).join('') console.log(theLi) document.querySelector('.list-group').innerHTML = theLi }) }) </script>
|
在 url 网址后面用?拼接格式:http://xxxx.com/xxx/xxx?参数名1=值1&参数名2=值2.参数名一般是后端规定的,值前端看情况传递即可
POST请求
1 2 3 4 5 6 7 8 9 10 11
| document.querySelector('.btn').addEventListener('click', () => { axios({ url: 'http://hmajax.itheima.net/api/register', method: 'POST', data: { username: 'itheima007', password: '7654321' } }) })
|
axios错误处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| document.querySelector('.btn').addEventListener('click', () => { axios({ url: 'http://hmajax.itheima.net/api/register', method: 'post', data: { username: 'itheima007', password: '7654321' } }).then(result => { console.log(result) }).catch(error => { console.log(error) console.log(error.response.data.message) alert(error.response.data.message) }) })
|
文件上传
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <input type="file" class="upload"> <img src="" alt="" class="my-img">
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> document.querySelector('.upload').addEventListener('change', e => { console.log(e.target.files[0]) const fd = new FormData() fd.append('img', e.target.files[0]) axios({ url: 'http://hmajax.itheima.net/api/uploadimg', method: 'POST', data: fd }).then(result => { console.log(result) const imgUrl = result.data.data.url document.querySelector('.my-img').src = imgUrl }) }) </script>
|
async await
- 概念:在 async 函数内,使用 await 关键字取代 then 函数,等待获取 Promise 对象成功状态的结果值
- 做法:使用 async 和 await 解决回调地狱问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
async function getData() { try { const pObj = await axios({ url: 'http://hmajax.itheima.net/api/province' }) const pname = pObj.data.list[0] const cObj = await axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } }) const cname = cObj.data.list[0] const aObj = await axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname, cname } }) const areaName = aObj.data.list[0]
document.querySelector('.province').innerHTML = pname document.querySelector('.city').innerHTML = cname document.querySelector('.area').innerHTML = areaName } catch (error) { console.dir(error) } }
getData()
|
请求报文
浏览器按照协议规定发送给服务器的内容
- 请求行:请求方法,URL,协议
- 请求头:以键值对的格式携带的附加信息,比如:Content-Type(指定了本次传递的内容类型)
- 空行:分割请求头,空行之后的是发送给服务器的资源
- 请求体:发送的资源
响应报文
服务器按照协议固定的格式,返回给浏览器的内容
- 响应行(状态行):协议,HTTP响应状态码,状态信息
- 响应头:以键值对的格式携带的附加信息,比如:Content-Type(告诉浏览器,本次返回的内容类型)
- 空行:分割响应头,控制之后的是服务器返回的资源
- 响应体:返回的资源
HTTP响应状态码: 1xx 信息,2xx 成功,3xx 重定向消息,4xx 客户端错误,5xx 服务端错误.
AJAX 原理-XMLHttpRequest
XMLHttpRequest(XHR)对象用于与服务器交互。通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。XMLHttpRequest 在 AJAX 编程中被大量使用。
语法
1 2 3 4 5 6 7 8
| const xhr = new XMLHttpRequest() xhr.open('请求方法', '请求url网址') xhr.addEventListener('loadend', () => { console.log(xhr.response) })
xhr.send()
|
POST传参请求
注意1:但是这次没有 axios 帮我们了,我们需要自己设置请求头 Content-Type:application/json,来告诉服务器端,我们发过去的内容类型是 JSON 字符串,让他转成对应数据结构取值使用
注意2:没有 axios 了,我们前端要传递的请求体数据,也没人帮我把 JS 对象转成 JSON 字符串了,需要我们自己转换
注意3:原生 XHR 需要在 send 方法调用时,传入请求体携带
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| document.querySelector('.reg-btn').addEventListener('click', () => { const xhr = new XMLHttpRequest() xhr.open('POST', 'http://hmajax.itheima.net/api/register') xhr.addEventListener('loadend', () => { console.log(xhr.response) })
xhr.setRequestHeader('Content-Type', 'application/json') const userObj = { username: 'itheima007', password: '7654321' } const userStr = JSON.stringify(userObj) xhr.send(userStr) })
|
Promise
Promise 对象用于表示一个异步操作的最终完成(或失败)及其结构值
1 2 3 4 5 6 7 8 9 10 11 12
| const p = new Promise((resolve, reject) => { })
p.then(result => { }).catch(error => { })
|
Promise.all
合并多个Promise 对象,等待所有同时成功完成(或某一个失败),做后续处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const bjPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '110100' } }) const shPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '310100' } }) const gzPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '440100' } }) const szPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '440300' } })
const p = Promise.all([bjPromise, shPromise, gzPromise, szPromise]) p.then(result => { console.log(result) const htmlStr = result.map(item => { return `<li>${item.data.data.area} --- ${item.data.data.weather}</li>` }).join('') document.querySelector('.my-ul').innerHTML = htmlStr }).catch(error => { console.dir(error) })
|
模拟axios原理
XHR和Promise默认axios原理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| function myAxios(config) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest()
if (config.params) { const paramsObj = new URLSearchParams(config.params) const queryString = paramsObj.toString() config.url += `?${queryString}` } xhr.open(config.method || 'GET', config.url)
xhr.addEventListener('loadend', () => { if (xhr.status >= 200 && xhr.status < 300) { resolve(JSON.parse(xhr.response)) } else { reject(new Error(xhr.response)) } }) if (config.data) { const jsonStr = JSON.stringify(config.data) xhr.setRequestHeader('Content-Type', 'application/json') xhr.send(jsonStr) } else { xhr.send() } }) }
document.querySelector('.reg-btn').addEventListener('click', () => { myAxios({ url: 'http://hmajax.itheima.net/api/register', method: 'POST', data: { username: 'itheima999', password: '666666' } }).then(result => { console.log(result) }).catch(error => { console.dir(error) }) })
|
同步代码和异步代码
同步代码:逐行执行,需原地等待结果后,才继续向下执行
异步代码 :调用后耗时,不阻塞代码继续执行(不必原地等待),在将来完成后触发回调函数传递结果
axios 全局拦截
请求拦截
1 2 3 4 5 6 7 8 9 10 11
| axios.interceptors.request.use(function (config) { const token = localStorage.getItem('token') token && (config.headers.Authorization = `Bearer ${token}`) return config; }, function (error) { return Promise.reject(error); });
|
响应拦截
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| axios.interceptors.response.use(function (response) { const result = response.data return result; }, function (error) { console.dir(error) if (error?.response?.status === 401) { alert('身份验证失败,请重新登录') localStorage.clear() location.href = '../login/index.html' } return Promise.reject(error); });
|
URL
什么是 URL ?
- 统一资源定位符,简称网址,用于定位网络中的资源(资源指的 是:网页,图片,数据,视频,音频等等)
URL 的组成?
- 协议,域名,资源路径(URL 组成有很多部分,我们先掌握这3个重要的部分即可)
什么是 http 协议 ?
- 叫超文本传输协议,规定了浏览器和服务器传递数据的格式(而格式具体有哪些稍后我们就会学到)
什么是域名 ?
- 标记服务器在互联网当中的方位,网络中有很多服务器,你想访问哪一台,就需要知道它的域名才可以
什么是资源路径 ?
- 一个服务器内有多个资源,用于标识你要访问的资源具体的位置。