HTTP协议、存储、Ajax
初识前后端通信
前后端通信的过程与概念解释
前后端的通信方式
慕课网
初识 HTTP
HTTP 报文
HTTP 方法
HTTP 状态码
初识 Cookie
document.cookie = 'username=alex;max-age=5';
document.cookie = 'age=18;domain=.imooc.com;max-age=5';
document.cookie; //username=alex;age=18
Cookie 的基本用法
创建 Cookie 时必须填写,其他属性可以使用默认值
如果包含非英文字母,写入时要用 encodeURIComponent() 编写
如果写入时编码,读取时要用 decodeURIComponent() 解码
失效的 Cookie,会浏览器清除
如果没有设置失效时间,默认会话结束后,Cookie会被清除
想Cookie长时间存在,可以设置 Expires 或 Max-Age
Expires 值为 Date 类型,表示具体什么时间过期
Max-Age 值为数字,表示当前时间加多少秒后过期,单位是秒
如果设置 Max-Age 的值0或负数,则 Cookie 会被删除
Domain 限定了访问 Cookie 的范围( 不同城下 )
使用 JS 只能写入/读取当前域或父域的Cookie,无法写入/读取其他域的Cookie
Path 限定了访问 Cookie的范围( 同城不同路径下 )
使用 JS 只能写入/读取当前路径和上级路径的 Cookie ,无法写入/读取其他路径的 Cookie
前端不能通过 JS 去设置一个 HttpOnly 类型的 Cookie,这种类型的 Cookie 只能是后端来设置
只要是 HttpOnly 类型的,通过 document.cookie 是获取不到的,也不能修改
Secure 限定了只有在使用了 https 而不是 http 的情况下才可以发送给服务器
Cookie 的属性
// 写入 Cookie
const set = (name, value, { maxAge, domain, path, secure } = {}) => {
let cookieText = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
if (typeof maxAge === 'number') {
cookieText += `; max-age=${maxAge}`;
}
if (domain) {
cookieText += `; domain=${domain}`;
}
if (path) {
cookieText += `; path=${path}`;
}
if (secure) {
cookieText += `; secure`;
}
document.cookie = cookieText;
// document.cookie='username=alex; max-age=5; domain='
};
// 通过 name 获取 cookie 的值
const get = name => {
name = `${encodeURIComponent(name)}`;
const cookies = document.cookie.split('; ');
for (const item of cookies) {
const [cookieName, cookieValue] = item.split('=');
if (cookieName === name) {
return decodeURIComponent(cookieValue);
}
}
return;
};
// 'username=alex; age=18; sex=male'
// ["username=alex", "age=18", "sex=male"]
// ["username","alex"]
// get('用户名');
// 根据 name、domain 和 path 删除 Cookie
const remove = (name, { domain, path } = {}) => {
set(name, '', { domain, path, maxAge: -1 });
};
export { set, get, remove };
Cookie 的注意事项
localStorage.setItem(‘username’:‘alex’);
localStorage.getItem(‘username’)
localStorage.removeltem(‘username’)
localStorage.celar(‘username’)
localStorage.length
初识 localStorage
localStorage 的注意事项
初识 Ajax
// 1.XMLHttpRequest
console.log(Ajax);
// Ajax 想要实现浏览器与服务器之间的异步通信,需要依靠 XMLHttpRequest,它是一个构造函数
// 不论是 XMLHttpRequest,还是 Ajax,都没有和具体的某种数据格式绑定
// 2.Ajax 的使用步骤
// 2.1.创建 xhr 对象
const xhr = new XMLHttpRequest();
// 2.2.监听事件,处理响应
// 当获取到响应后,会触发 xhr 对象的 readystatechange 事件,可以在该事件中对响应进行处理
xhr.addEventListener('readystatechange', () => {}, fasle);
xhr.onreadystatechange = () => {
if (xhr.readyState !== 4) return;
// HTTP CODE
// 获取到响应后,响应的内容会自动填充 xhr 对象的属性
// xhr.status:HTTP 200 404
// xhr.statusText:HTTP 状态说明 OK Not Found
if ((xhr.status >= 200) & (xhr.status < 300) || xhr.status === 304) {
// console.log('正常使用响应数据');
console.log(xhr.responseText);
}
};
// readystatechange 事件也可以配合 addEventListener 使用,不过要注意,IE6~8 不支持 addEventListener
// 为了兼容性,readystatechange 中不使用 this,而是直接使用 xhr
// 由于兼容性的原因,最好放在 open 之前
// readystatechange 事件监听 readyState 这个状态的变化
// 它的值从 0 ~ 4,一共 5 个状态
// 0:未初始化。尚未调用 open()
// 1:启动。已经调用 open(),但尚未调用 send()
// 2:发送。已经调用 send(),但尚未接收到响应
// 3:接收。已经接收到部分响应数据
// 4:完成。已经接收到全部响应数据,而且已经可以在浏览器中使用了
// 2.3.准备发送请求
xhr.open(
'HTTP 方法 GET、POST、PUT、DELETE',
'地址 URL https://www.imooc.com/api/http/search/suggest?words=js ./index.html ./index.xml ./index.txt',
true
);
// 调用 open 并不会真正发送请求,而只是做好发送请求前的准备工作
// 2.3.发送请求
// 调用 send() 正式发送请求
// send() 的参数是通过请求体携带的数据
xhr.send(null);
// 3.使用 Ajax 完成前后端通信
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState !== 4) return;
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.responseText);
console.log(typeof xhr.responseText);
}
};
xhr.open('GET', url, true);
xhr.send(null);
// 1.携带数据
// GET 请求不能通过请求体携带数据,但可以通过请求头携带
const url =
'https://www.imooc.com/api/http/search/suggest?words=js&username=alex&age=18';
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState != 4) return;
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.responseText);
}
};
xhr.open('GET', url, true);
xhr.send(null);
// 不会报错,但不会发送数据
xhr.send('sex=male');
// 2.数据编码
// 如果携带的数据是非英文字母的话,比如说汉字,就需要编码之后再发送给后端,不然会造成乱码问题
// 可以使用 encodeURIComponent() 编码
const url = `https://www.imooc.com/api/http/search/suggest?words=${encodeURIComponent(
'前端'
)}`;
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState != 4) return;
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.responseText);
}
};
xhr.open('GET', url, true);
xhr.send(null);
// 1.携带数据
// POST 请求主要通过请求体携带数据,同时也可以通过请求头携带
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState != 4) return;
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.responseText);
}
};
xhr.open('POST', url, true);
// 如果想发送数据,直接写在 send() 的参数位置,一般是字符串
// xhr.send('username=alex&age=18');
// 不能直接传递对象,需要先将对象转换成字符串的形式
xhr.send({
username: 'alex',
age: 18
});
// [object Object]
// 2.数据编码
xhr.send(`username=${encodeURIComponent('张三')}&age=18`);
// 1.JSON 是什么
// Ajax 发送和接收数据的一种格式
// XML
// username=alex&age=18
// JSON
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState != 4) return;
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.responseText);
}
};
xhr.open('GET', url, true);
xhr.send(null);
// {"code":200,"data":[{"word":"jsp"},{"word":"js"},{"word":"json"},{"word":"js \u5165\u95e8"},{"word":"jstl"}]}
// HTML/XML
// JSON 全称是 JavaScript Object Notation
// 2.为什么需要 JSON
// JSON 有 3 种形式,每种形式的写法都和 JS 中的数据类型很像,可以很轻松的和 JS 中的数据类型互相转换
// JS->JSON->PHP/Java
// PHP/Java->JSON->JS
// 1.简单值形式
// .json
// JSON 的简单值形式就对应着 JS 中的基础数据类型
// 数字、字符串、布尔值、null
// 注意事项
// ① JSON 中没有 undefined 值
// ② JSON 中的字符串必须使用双引号
// ③ JSON 中是不能注释的
// 2.对象形式
// JSON 的对象形式就对应着 JS 中的对象
// 注意事项
// JSON 中对象的属性名必须用双引号,属性值如果是字符串也必须用双引号
// JSON 中只要涉及到字符串,就必须使用双引号
// 不支持 undefined
// 3.数组形式
// JSON 的数组形式就对应着 JS 中的数组
// [1, "hi", null]
// 注意事项
// 数组中的字符串必须用双引号
// JSON 中只要涉及到字符串,就必须使用双引号
// 不支持 undefined
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState != 4) return;
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.responseText);
console.log(typeof xhr.responseText);
}
};
// xhr.open('GET', './plain.json', true); //"str"
// xhr.open('GET', './obj.json', true);
xhr.open('GET', './arr.json', true);
xhr.send(null);
[
{
"id": 1,
"username": "张三",
"comment": "666"
},
{
"id": 2,
"username": "李四",
"comment": "999 6翻了"
}
]
{
"name": "张三",
"age": 18,
"hobby": ["足球", "乒乓球"],
"family": {
"father": "张老大",
"mother": "李四"
}
}
// 1.JSON.parse()
// JSON.parse() 可以将 JSON 格式的字符串解析成 JS 中的对应值
// 一定要是合法的 JSON 字符串,否则会报错
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState != 4) return;
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.responseText);
console.log(typeof xhr.responseText);
console.log(JSON.parse(xhr.responseText));
console.log(JSON.parse(xhr.responseText).data);
}
};
xhr.open('GET', './plain.json', true);
xhr.open('GET', './obj.json', true);
xhr.open('GET', './arr.json', true);
xhr.open(
'GET',
'https://www.imooc.com/api/http/search/suggest?words=js',
true
);
xhr.send(null);
// 2.JSON.stringify()
// JSON.stringify() 可以将 JS 的基本数据类型、对象或者数组转换成 JSON 格式的字符串
console.log(
JSON.stringify({
username: 'alex',
age: 18
})
);
const xhr = new XMLHttpRequest();
xhr.open(
'POST',
'https://www.imooc.com/api/http/search/suggest?words=js',
true
);
xhr.send(
JSON.stringify({
username: 'alex',
age: 18
})
);
// 3.使用 JSON.parse() 和 JSON.stringify() 封装 localStorage
import { get, set, remove, clear } from './storage.js';
set('username', 'alex');
console.log(get('username'));
set('zs', {
name: '张三',
age: 18
});
console.log(get('zs'));
remove('username');
clear();
const storage = window.localStorage;
// 设置
const set = (key, value) => {
// {
// username: 'alex'
// }
storage.setItem(key, JSON.stringify(value));
};
// 获取
const get = key => {
// 'alex'
// {
// "username": "alex"
// }
return JSON.parse(storage.getItem(key));
};
// 删除
const remove = key => {
storage.removeItem(key);
};
// 清空
const clear = () => {
storage.clear();
};
export { set, get, remove, clear };
// 1.跨域是什么
// 同域,不是跨域
// const url = './index.html';
// http://127.0.0.1:5500
// 不同域,跨域,被浏览器阻止
// const url = 'https://www.imooc.com';
// const xhr = new XMLHttpRequest();
// Access to XMLHttpRequest at 'https://www.imooc.com/' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource
// 向一个域发送请求,如果要请求的域和当前域是不同域,就叫跨域
// 不同域之间的请求,就是跨域请求
xhr.onreadystatechange = () => {
if (xhr.readyState != 4) return;
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.responseText);
}
};
xhr.open('GET', url, true);
xhr.send(null);
// 2.什么是不同域,什么是同域
// https(协议)://www.imooc.com(域名):443(端口号)/course/list(路径)
// 协议、域名、端口号,任何一个不一样,就是不同域
// 与路径无关,路径一不一样无所谓
// 不同域
// https://www.imooc.com:443/course/list
// http://www.imooc.com:80/course/list
// http://www.imooc.com:80/course/list
// http://m.imooc.com:80/course/list
// http://imooc.com:80/course/list
// 同域
// http://imooc.com:80
// http://imooc.com:80/course/list
// 3.跨域请求为什么会被阻止
// 阻止跨域请求,其实是浏览器本身的一种安全策略--同源策略
// 其他客户端或者服务器都不存在跨域被阻止的问题
// 4.跨域解决方案
// ① CORS 跨域资源共享
// ② JSONP
// 优先使用 CORS 跨域资源共享,如果浏览器不支持 CORS 的话,再使用 JSONP
// 1.CORS 是什么 由后端负责 前端不用书写
const url = 'https://www.imooc.com';
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState != 4) return;
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.responseText);
}
};
xhr.open('GET', url, true);
xhr.send(null);
// Access-Control-Allow-Origin: *
// 表明允许所有的域名来跨域请求它,* 是通配符,没有任何限制
// 只允许指定域名的跨域请求
// Access-Control-Allow-Origin: http://127.0.0.1:5500
// 2.使用 CORS 跨域的过程
// ① 浏览器发送请求
// ② 后端在响应头中添加 Access-Control-Allow-Origin 头信息
// ③ 浏览器接收到响应
// ④ 如果是同域下的请求,浏览器不会额外做什么,这次前后端通信就圆满完成了
// ⑤ 如果是跨域请求,浏览器会从响应头中查找是否允许跨域访问
// ⑥ 如果允许跨域,通信圆满完成
// ⑦ 如果没找到或不包含想要跨域的域名,就丢弃响应结果
// 3.CORS 的兼容性
// IE10 及以上版本的浏览器可以正常使用 CORS
// https://caniuse.com/
// 1.JSONP 的原理
// script 标签跨域不会被浏览器阻止
// JSONP 主要就是利用 script 标签,加载跨域文件
// 2.使用 JSONP 实现跨域
// 服务器端准备好 JSONP 接口
// https://www.imooc.com/api/http/jsonp?callback=handleResponse
// 动态加载 JSONP 接口
const script = document.createElement('script');
script.src ='https://www.imooc.com/api/http/jsonp?callback=handleResponse';
document.body.appendChild(script);
// 声明函数
const handleResponse = data => {
console.log(data);
};
<
//相当于
// 1.responseType 和 response 属性
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState != 4) return;
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
// 文本形式的响应内容
// responseText 只能在没有设置 responseType 或者 responseType = '' 或 'text' 的时候才能使用
// console.log('responseText:', xhr.responseText);
// 可以用来替代 responseText
console.log('response:', xhr.response);
// console.log(JSON.parse(xhr.responseText));
}
};
xhr.open('GET', url, true);
// xhr.responseType = '';
// xhr.responseType = 'text';
xhr.responseType = 'json';
xhr.send(null);
// IE6~9 不支持,IE10 开始支持
// 2.timeout 属性
// 设置请求的超时时间(单位 ms)
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState != 4) return;
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.response);
}
};
xhr.open('GET', url, true);
xhr.timeout = 10000; //单位ms
xhr.send(null);
// IE6~7 不支持,IE8 开始支持
// 3.withCredentials 属性
// 指定使用 Ajax 发送请求时是否携带 Cookie
// 使用 Ajax 发送请求,默认情况下,同域时,会携带 Cookie;跨域时,不会
// xhr.withCredentials = true;
// 最终能否成功跨域携带 Cookie,还要看服务器同不同意
const url = 'https://www.imooc.com/api/http/search/suggest?words=js'; //跨域
// const url = './index.html'; //同域
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState != 4) return;
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.response);
}
};
xhr.open('GET', url, true);
xhr.withCredentials = true;
xhr.send(null);
// IE6~9 不支持,IE10 开始支持
// 1.abort()
// 终止当前请求
// 一般配合 abort 事件一起使用
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState != 4) return;
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.response);
}
};
xhr.open('GET', url, true);
xhr.send(null);
xhr.abort();
// 2.setRequestHeader()
// 可以设置请求头信息
// xhr.setRequestHeader(头部字段的名称, 头部字段的值);
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
// const url = 'https://www.imooc.com/api/http/json/search/suggest?words=js';
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState != 4) return;
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.response);
}
};
xhr.open('POST', url, true);
// 请求头中的 Content-Type 字段用来告诉服务器,浏览器发送的数据是什么格式的
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// xhr.setRequestHeader('Content-Type', 'application/json');
// xhr.send(null);
xhr.send('username=alex&age=18');
// xhr.send(
// JSON.stringify({
// username: 'alex'
// })
// 1.load 事件
// 响应数据可用时触发相当于onreadystatechange
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();
// xhr.onload = () => {
// if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
// console.log(xhr.response);
// }
// };
xhr.addEventListener(
'load',
() => {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.response);
}
},
false
);
xhr.open('GET', url, true);
xhr.send(null);
// IE6~8 不支持 load 事件
// 2.error 事件
// 请求发生错误时触发
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const url = 'https://www.iimooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();
xhr.addEventListener(
'load',
() => {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.response);
}
},
false
);
xhr.addEventListener(
'error',
() => {
console.log('error');
},
false
);
xhr.open('GET', url, true);
xhr.send(null);
// IE10 开始支持
// 3.abort 事件
// 调用 abort() 终止请求时触发
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();
xhr.addEventListener(
'load',
() => {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.response);
}
},
false
);
xhr.addEventListener(
'abort',
() => {
console.log('abort');
},
false
);
xhr.open('GET', url, true);
xhr.send(null);
xhr.abort();
// IE10 开始支持
// 4.timeout 事件
// 请求超时后触发
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();
xhr.addEventListener(
'load',
() => {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.response);
}
},
false
);
xhr.addEventListener(
'timeout',
() => {
console.log('timeout');
},
false
);
xhr.open('GET', url, true);
xhr.timeout = 10;
xhr.send(null);
// IE8 开始支持
FormData
封装 Ajax
import Ajax from './ajax.js';
const ajax = (url, options) => {
return new Ajax(url, options).getXHR();
};
const get = (url, options) => {
return ajax(url, { ...options, method: 'GET' });
};
const getJSON = (url, options) => {
return ajax(url, { ...options, method: 'GET', responseType: 'json' });
};
const post = (url, options) => {
return ajax(url, { ...options, method: 'POST' });
};
export { ajax, get, getJSON, post };
// 常量
export const HTTP_GET = 'GET';
export const CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded';
export const CONTENT_TYPE_JSON = 'application/json';
// 工具函数
// 数据序列化成 urlencoded 格式的字符串
const serialize = param => {
const results = [];
for (const [key, value] of Object.entries(param)) {
results.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
}
// ['username=alex', 'age=18'];
return results.join('&');
};
// 数据序列化成 JSON 格式的字符串
const serializeJSON = param => {
return JSON.stringify(param);
};
// 给 URL 添加参数
// www.imooc.com?words=js&
const addURLData = (url, data) => {
if (!data) return '';
const mark = url.includes('?') ? '&' : '?';
return `${mark}${data}`;
};
export { serialize, addURLData, serializeJSON };
// 常量
import { HTTP_GET, CONTENT_TYPE_FORM_URLENCODED } from './constants.js';
// 默认参数
const DEFAULTS = {
method: HTTP_GET,
// 请求头携带的数据
params: null,
// params: {
// username: 'alex',
// age: 18
// }
// username=alex&age=18
// 请求体携带的数据
data: null,
// data: {
// username: 'alex',
// age: 18
// }
// data: FormData 数据
contentType: CONTENT_TYPE_FORM_URLENCODED,
responseType: '',
timeoutTime: 0,
withCredentials: false,
// 方法
success() {},
httpCodeError() {},
error() {},
abort() {},
timeout() {}
};
export default DEFAULTS;
// 常量
import {
HTTP_GET,
CONTENT_TYPE_FORM_URLENCODED,
CONTENT_TYPE_JSON
} from './constants.js';
// 工具函数
import { serialize, addURLData, serializeJSON } from './utils.js';
// 默认参数
import DEFAULTS from './defaults.js';
// Ajax 类
class Ajax {
constructor(url, options) {
this.url = url;
this.options = Object.assign({}, DEFAULTS, options);
// 初始化
this.init();
}
// 初始化
init() {
const xhr = new XMLHttpRequest();
this.xhr = xhr;
// 绑定响应事件处理程序
this.bindEvents();
xhr.open(this.options.method, this.url + this.addParam(), true);
// 设置 responseType
this.setResponseType();
// 设置跨域是否携带 cookie
this.setCookie();
// 设置超时
this.setTimeout();
// 发送请求
this.sendData();
}
// 绑定响应事件处理程序
bindEvents() {
const xhr = this.xhr;
const { success, httpCodeError, error, abort, timeout } = this.options;
// load
xhr.addEventListener(
'load',
() => {
if (this.ok()) {
success(xhr.response, xhr);
} else {
httpCodeError(xhr.status, xhr);
}
},
false
);
// error
// 当请求遇到错误时,将触发 error 事件
xhr.addEventListener(
'error',
() => {
error(xhr);
},
false
);
// abort
xhr.addEventListener(
'abort',
() => {
abort(xhr);
},
false
);
// timeout
xhr.addEventListener(
'timeout',
() => {
timeout(xhr);
},
false
);
}
// 检测响应的 HTTP 状态码是否正常
ok() {
const xhr = this.xhr;
return (xhr.status >= 200 && xhr.status < 300) || xhr.status === 304;
}
// 在地址上添加数据
addParam() {
const { params } = this.options;
if (!params) return '';
return addURLData(this.url, serialize(params));
}
// 设置 responseType
setResponseType() {
this.xhr.responseType = this.options.responseType;
}
// 设置跨域是否携带 cookie
setCookie() {
if (this.options.withCredentials) {
this.xhr.withCredentials = true;
}
}
// 设置超时
setTimeout() {
const { timeoutTime } = this.options;
if (timeoutTime > 0) {
this.xhr.timeout = timeoutTime;
}
}
// 发送请求
sendData() {
const xhr = this.xhr;
if (!this.isSendData()) {
return xhr.send(null);
}
let resultData = null;
const { data } = this.options;
// 发送 FormData 格式的数据
if (this.isFormData()) {
resultData = data;
} else if (this.isFormURLEncodedData()) {
// 发送 application/x-www-form-urlencoded 格式的数据
this.setContentType(CONTENT_TYPE_FORM_URLENCODED);
resultData = serialize(data);
} else if (this.isJSONData()) {
// 发送 application/json 格式的数据
this.setContentType(CONTENT_TYPE_JSON);
resultData = serializeJSON(data);
} else {
// 发送其他格式的数据
this.setContentType();
resultData = data;
}
xhr.send(resultData);
}
// 是否需要使用 send 发送数据
isSendData() {
const { data, method } = this.options;
if (!data) return false;
if (method.toLowerCase() === HTTP_GET.toLowerCase()) return false;
return true;
}
// 是否发送 FormData 格式的数据
isFormData() {
return this.options.data instanceof FormData;
}
// 是否发送 application/x-www-form-urlencoded 格式的数据
isFormURLEncodedData() {
return this.options.contentType
.toLowerCase()
.includes(CONTENT_TYPE_FORM_URLENCODED);
}
// 是否发送 application/json 格式的数据
isJSONData() {
return this.options.contentType.toLowerCase().includes(CONTENT_TYPE_JSON);
}
// 设置 Content-Type
setContentType(contentType = this.options.contentType) {
if (!contentType) return;
this.xhr.setRequestHeader('Content-Type', contentType);
}
// 获取 XHR 对象
getXHR() {
return this.xhr;
}
}
export default Ajax;
使用 Promise 改造封装好的 Ajax
import Ajax from './ajax.js';
// 常量
import {
ERROR_HTTP_CODE,
ERROR_REQUEST,
ERROR_TIMEOUT,
ERROR_ABORT,
ERROR_HTTP_CODE_TEXT,
ERROR_REQUEST_TEXT,
ERROR_TIMEOUT_TEXT,
ERROR_ABORT_TEXT
} from './constants.js';
const ajax = (url, options) => {
// return new Ajax(url, options).getXHR();
let xhr;
const p = new Promise((resolve, reject) => {
xhr = new Ajax(url, {
...options,
...{
success(response) {
resolve(response);
},
httpCodeError(status) {
reject({
type: ERROR_HTTP_CODE,
text: `${ERROR_HTTP_CODE_TEXT}: ${status}`
});
},
error() {
reject({
type: ERROR_REQUEST,
text: ERROR_REQUEST_TEXT
});
},
abort() {
reject({
type: ERROR_ABORT,
text: ERROR_ABORT_TEXT
});
},
timeout() {
reject({
type: ERROR_TIMEOUT,
text: ERROR_TIMEOUT_TEXT
});
}
}
}).getXHR();
});
p.xhr = xhr;
p.ERROR_HTTP_CODE = ERROR_HTTP_CODE;
p.ERROR_REQUEST = ERROR_REQUEST;
p.ERROR_TIMEOUT = ERROR_TIMEOUT;
p.ERROR_ABORT = ERROR_ABORT;
return p;
};
const get = (url, options) => {
return ajax(url, { ...options, method: 'GET' });
};
const getJSON = (url, options) => {
return ajax(url, { ...options, method: 'GET', responseType: 'json' });
};
const post = (url, options) => {
return ajax(url, { ...options, method: 'POST' });
};
export { ajax, get, getJSON, post };
// 常量
export const HTTP_GET = 'GET';
export const CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded';
export const CONTENT_TYPE_JSON = 'application/json';
export const ERROR_HTTP_CODE = 1;
export const ERROR_HTTP_CODE_TEXT = 'HTTP 状态码异常';
export const ERROR_REQUEST = 2;
export const ERROR_REQUEST_TEXT = '请求被阻止';
export const ERROR_TIMEOUT = 3;
export const ERROR_TIMEOUT_TEXT = '请求超时';
export const ERROR_ABORT = 4;
export const ERROR_ABORT_TEXT = '请求终止';
utils.js、defaults.js、ajax.js都一致
搜索提示
二级菜单
多个 Ajax 请求的并发执行
axios
Fetch
Fetch