AJAX
- 在 js 中有内置的构造函数来创建 ajax 对象
- 创建 ajax 对象以后,我们就使用 ajax 对象的方法去发送请求和接受响应
一、创建ajax
1、创建一个ajax
const xhr = new XMLHttpRequest()
- 上面就是有了一个 ajax 对象
- 我们就可以使用这个
xhr 对象来发送 ajax 请求了
2、配置ajax
- 向谁发送请求?以什么方式发送请求?这两个问题的答案,在接口文件中
- xhr.open('以什么方式请求,目前开发中只有post/get', '向谁发送请求', '第三个参数暂时不讲')
xhr.open('GET', 'http://localhost:8888/test/first')
3、发送ajax
xhr.send()
4、监听请求完成的时间
- 请求完成的时候,说明数据已经给到我们前端,我们开始使用
xhr.onload = function () {
console.log(xhr.responseText)
}
二、ajax的异步问题
- 其实就是 配置 ajax 的第三个参数,这个参数默认是 true 表示当前的请求是 异步
1、异步: 1 2 3 4
-
- 创建 (同步)
-
- 配置 (同步)
-
- 发送 (异步)
-
- 监听 (同步)
const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://localhost:8888/test/first')
xhr.send()
xhr.onload = function () {
console.log(xhr.responseText)
}
2、异步: 1 2 4 3
-
- 创建 (同步)
-
- 配置 (同步)
-
- 监听 (同步)
-
- 发送 (异步)
const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://localhost:8888/test/first')
xhr.onload = function () {
console.log(xhr.responseText)
}
xhr.send()
3、同步: 1 2 4 3
-
- 创建 (同步)
-
- 配置 (同步)
-
- 监听 (同步)
-
- 发送 (异步)
const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://localhost:8888/test/first', false)
xhr.onload = function () {
console.log(xhr.responseText)
}
xhr.send()
4、同步: 1 2 3 4
-
- 创建 (同步)
-
- 配置 (同步)
-
- 发送 (异步)
-
- 监听 (同步)
const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://localhost:8888/test/first', false)
xhr.send()
xhr.onload = function () {
console.log(xhr.responseText)
}
三、ajax的状态码
- 利用了一个数字表明 ajax 当前运行到那一步了
- 0: ajax 创建完毕
- 1: ajax 配置完毕
- 2: ajax 发送完毕 (后端已经对请求做出响应, 并把请求返回给 浏览器)
- 3: 浏览器开始解析后端返回的内容, 如果返回的数据比较少, 那么此时就可以使用数据了, 但是有可能没有解析完毕, 数据不完整, 所以不推荐在这里使用数据
- 4: 浏览器的解析的内容已经全部处理完毕, 我们可以开始使用数据了
const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://localhost:8888/test/first')
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
console.log('4 ---> 浏览器解析完毕数据', xhr.responseText)
}
}
xhr.onload = function () {
console.log('请求完毕 onload 加载: ', xhr.responseText)
}
四、http协议
- 当前协议规定 请求 只能是 前端发起的, 并且在传输过程中, 只能传递字符串
-
- 建立连接:览器和服务器建立连接
-
- 发送请求:如要携带一些参数, 那么需要以请求报文的形式传递,览器进行组装, 我们只需要传递一些对应的信息
-
- 接收响应:根据请求报文内的相关信息, 确定现在需要做什么事情, 并把必要的数据进行返回;返回的内容需要放在 响应报文中
-
- 关闭连接: 浏览器和服务器的连接到此结束
- 综上所述, 我们的每一个请求都是完全独立的, 前一个请求和后一个请求没有任何关联哪怕两次请求之间的间隔很短, 那也没有任何关联
- HTTP协议请求状态码:
- 100~199: 连接正在进行中(持续进行)
- 200~299: 表明连接成功
- 300~399: 表明重定向
- 400~499: 表明前端错误 (没权限/传参错误)
- 500~599: 表明后端错误
五、请求方式的差异
- GET:获取的含义
- POST:提交的含义
请求方式最大的差异就是传参
1.传参的方式
- GET:直接在地址后边拼接参数即可, 格式类似于以前的 查询字符串
- POST:在请求体内书写 (其实就是 xhr.send(这小括号内))
2.传参的大小
- GET:2kb 左右
- POST:原则上没有限制, 但是我们可以在后端添加限制
3.传参的安全性
- GET:明文传输, 相对不安全
- POST:密文传输, 相对安全
4.传参的格式
- GET:传递的是查询字符串格式
- POST:原则上也没有限制, 但是传参的时候需要通过 content-type 指定我们传参的格式
六、GET/POST测试请求
1.GET测试请求
const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://localhost:8888/test/first')
xhr.send()
xhr.onload = function () {
console.log(xhr.responseText)
}
const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://localhost:8888/test/second')
xhr.send()
xhr.onload = function () {
const res = JSON.parse(xhr.responseText)
if (res.code === 0) {
console.log('此时可能请求失败');
return
}
如果代码能够运行到这里, 说明请求成功, 我们可以做成功后的一些事情
console.log('此时请求完毕',res);
}
const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://localhost:8888/test/third?age=18')
xhr.send()
xhr.onload = function () {
const res = JSON.parse(xhr.responseText)
if (res.code === 0) {
console.log('此时请求失败');
return
}
console.log('此时请求完毕', res);
}
2.POST测试请求
- post 的参数一定书写在 xhr.send() 的小括号中,并且 我们也可以传递查询字符串
- 如果是 post 方式, 并且需要携带参数, 那么需要加一步 设置请求头
- 参数是JSON字符串
xhr.setRequestHeader('content-type', 'application/json')
- 参数是查询字符串
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
const xhr = new XMLHttpRequest()
xhr.open('POST', 'http://localhost:8888/test/fourth')
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
xhr.send('name=王慧雨&age=18')
xhr.onload = function () {
const res = JSON.parse(xhr.responseText)
console.log('请求成功了', res)
}
七、案例
1、分页
<script>
const myUl = document.querySelector('ul')
const prev = document.querySelector('.prev')
const total = document.querySelector('.total')
const next = document.querySelector('.next')
const select = document.querySelector('select')
let currentPage = 1
let pageSize = 4
let totalNum = 0
function fn(data) {
const { list } = data
myUl.innerHTML = list.reduce(function (prev, item) {
return prev + `
<li>
<img src="${item.img_big_logo}" alt="">
<p>${item.title}</p>
</li>
`
}, '')
totalNum = data.total
total.innerHTML = currentPage + ' / ' + totalNum
prev.className = currentPage === 1 ? 'prev disable' : 'prev'
next.className = currentPage === totalNum ? 'next disable' : 'next'
}
function getData() {
const xhr = new XMLHttpRequest()
xhr.open('GET', `http://localhost:8888/goods/list?current=${currentPage}&pagesize=${pageSize}`)
xhr.send()
xhr.onload = function () {
const res = JSON.parse(xhr.responseText)
if (res.code !== 1) {
return alert(res.message)
}
fn(res)
}
}
getData()
prev.onclick = function () {
if (currentPage === 1) return
currentPage--
getData()
}
next.onclick = function () {
if (currentPage === totalNum) return
currentPage++
getData()
}
select.onchange = function () {
pageSize = select.value - 0
currentPage = 1
getData()
}
八、封装AJax
function objToStr(obj) {
let str = "";
for (let key in obj) {
const value = obj[key];
str += `${key}=${value}&`;
}
str = str.slice(0, str.length - 1);
return str;
}
function newFn(baseUrl) {
return function myAjax(options) {
if (options.url === undefined)
throw new Error("url 为必传项, 您必须传递");
if (
!(
options.method === undefined ||
/^(get|post)$/i.test(options.method)
)
) {
throw new Error(
"method 的值 要么为 get 要么为 post, 并且不区分大小写"
);
}
if (
!(
options.async === undefined ||
Object.prototype.toString.call(options.async) ===
"[object Boolean]"
)
) {
throw new Error("async 的值 只能为布尔值, 默认为 true");
}
if (
!(
options.data === undefined ||
typeof options.data === "string" ||
Object.prototype.toString.call(options.data) ===
"[object Object]"
)
) {
throw new Error(
"data 的值 可以为字符串也可以为对象, 默认为 空字符串"
);
}
if (
!(
options.header === undefined ||
Object.prototype.toString.call(options.header) ===
"[object Object]"
)
) {
throw new Error("header 必须传递一个对象, 也可以不传");
}
if (
!(
options.dataType === undefined ||
/^(string|json)$/i.test(options.dataType)
)
) {
throw new Error("dataType 目前仅支持 string 或 json, 默认为 json");
}
const _options = {
url: baseUrl + options.url,
method: options.method || "GET",
async: options.async ?? true,
data: options.data || "",
header: {
"content-type": "application/x-www-form-urlencoded",
...options.header,
},
dataType: options.dataType || "json",
};
if (
Object.prototype.toString.call(_options.data) === "[object Object]"
) {
_options.data = objToStr(_options.data);
}
_options.url = /^get$/i.test(_options.method)
? _options.url + "?" + _options.data
: _options.url;
return new Promise(function (res, rej) {
const xhr = new XMLHttpRequest();
xhr.open(_options.method, _options.url, _options.async);
_options.header.authorization &&
xhr.setRequestHeader(
"authorization",
_options.header.authorization
);
if (_options.data !== "" && /^post$/i.test(_options.method)) {
xhr.setRequestHeader(
"content-type",
_options.header["content-type"]
);
}
/^post$/i.test(_options.method)
? xhr.send(_options.data)
: xhr.send();
xhr.onload = function () {
if (_options.dataType === "string") {
return res({
code: 1,
msg: "请求成功",
info: xhr.responseText,
});
}
try {
const newData = JSON.parse(xhr.responseText);
res({
code: 1,
msg: "请求成功",
info: newData,
});
} catch (error) {
res({
code: 0,
msg: "请求失败",
info: error,
});
}
};
});
};
}
export const myAjax = newFn(baseUrl);