初识 Ajax
- Ajax 是什么
Ajax 是 Asynchronous JavaScript and XML(异步 JavaScript 和 XML)的简写
Ajax 中的异步:可以异步地向服务器发送请求,在等待响应的过程中,不会阻塞当前页面,浏览器可以做自己的事情。直到成功获取响应后,浏览器才开始处理响应数据
XML(可扩展标记语言)是前后端数据通信时传输数据的一种格式
XML 现在已经不怎么用了,现在比较常用的是 JSON
Ajax 其实就是浏览器与服务器之间的一种异步通信方式
使用 Ajax 可以在不重新加载整个页面的情况下,对页面的某部分进行更新
Ajax 的基本用法
- XMLHttpRequest
Ajax 想要实现浏览器与服务器之间的异步通信,需要依靠 XMLHttpRequest,它是一个构造函数
不论是 XMLHttpRequest,还是 Ajax,都没有和具体的某种数据格式绑定
- Ajax 的使用步骤
2.1 创建 xhr 对象
const xhr = new XMLHttpRequest();
2.4 监听事件,处理响应
当获取到响应后,会触发 xhr 对象的 readystatechange 事件,可以在该事件中对响应进行处理
xhr.addEventListener('readystatechange', () => {}, false);
xhr.onreadystatechange = () => {
if (xhr.readyState !== 4) return;
// xhr.status: HTTP 200 404
// xhr.statusText: HTTP 状态说明 OK Not Found
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
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.2 准备发送请求
调用 open 并不会真正发送请求,而只是做好发送请求前的准备工作
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 是,只用 true 方式'
);
2.3 发送请求
调用 send() 正式发送请求
send() 的参数是通过请求体携带的数据
xhr.send(null); // GET 方法不传送请求体,传 null 是为了兼容性的问题
- 使用 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 === 403) {
console.log(xhr.responseText);
}
}
xhr.open('GET', url, true);
xhr.send(null);
GET 请求
- 携带数据
GET 请求不能通过请求体携带数据,但是可以通过请求头携带
const url = 'https://www.imooc.com/api/http/search/suggest?words=js&name=zs&age=18';
GET 请求时,send() 中写入数据不会报错,但不会发送数据
- 数据编码
如果携带的数据是非英文字母的话,比如说汉字,就需要编码之后再发送给后端,不然会造成乱码问题,可以使用 encodeURIComponent() 编码
const url = `https://www.imooc.com/api/http/search/suggest?words=${encodeURIComponent('前端')}`;
POST 请求
- 携带数据
POST 请求主要通过请求体携带数据,同时也可以通过请求头携带
如果想发送数据,直接写在 send() 的参数位置,一般是字符串
不能直接传递对象,需要先将对象转换成字符串的形式
// 其中一种数据传输方式
xhr.send('username=zs&age=18');
- 数据编码
xhr.send(`username=${encodeURIComponent('张三')}&age=18`);
初识 JSON
- JSON 是什么
Ajax 发送和接收数据的一种格式
XML
username=zs&age=18
JSON
JSON 全称是 JavaScript Object Notation
- 为什么需要 JSON
JSON 有 3 种形式,每种形式的写法都和 JS 中的数据类型很像,可以很轻松的和 JS 中的数据类型互相转换
JSON 的 3 种形式
- 简单值形式
.json 文件
JSON 的简单值形式就对应着 JS 中的基础数据类型
数字、字符串、布尔值、null
5
"str"
true
null
注意事项
(1) JSON 中没有 undefined
(2) JSON 中的字符串必须使用双引号
(3) JSON 中是不能注释的
- 对象形式
JSON 的对象形式就对应着 JS 中的对象
注意事项
JSON 中对象的属性名必须用双引号,属性值如果是字符串也必须用双引号
JSON 中只要涉及到字符串,就必须使用双引号
不支持 undefined
{
"username": "张明明",
"age": 18,
"hobby": ["足球", "篮球"],
"family": {
"father": "张三",
"mother": "李四"
}
}
- 数组形式
JSON 的数组形式就对应着 JS 中的数组
[1, "hi", null]
注意事项
数组中的字符串必须用双引号
JSON 中只要涉及到字符串,就必须使用双引号
不支持 undefined
JSON 的常用方法
- JSON.parse()
JSON.parse() 可以将 JSON 格式的字符串解析成 JS 中的对应值
一定要是合法的 JSON 字符串,否则会报错
console.log(JSON.parse(xhr.responseText));
- JSON.stringify()
JSON.stringify() 可以将 JS 的基本数据类型、对象或者数组转换成 JSON 格式的字符串
xhr.send(JSON.stringify({
username: 'zs',
age: 18
}));
- 使用 JSON.parse() 和 JSON.stringify() 封装 localStorage
初识跨域
-
跨域是什么
向一个域发送请求,如果要请求的域和当前域是不同域,就叫跨域
不同域之间的请求,就是跨域请求
不同域,跨域,被浏览器阻止 -
什么是不同域,什么是同域
协议、域名、端口号,任何一个不一样,就是不同域
与路径无关,路径一不一样无所谓 -
跨域请求为什么会被阻止
阻止跨域请求,其实是浏览器本身的一种安全策略–同源策略
其他客户端或者服务器都不存在跨域被阻止的问题 -
跨域解决方案
(1) CORS 跨域资源共享
(2) JSONP
优先使用 CORS 跨域组员共享,如果浏览器不支持 CORS 的话,再使用 JSONP
CORS 跨域资源共享
- CORS 是什么
Access-Control-Allow-Origin: *
在响应头部加上该属性,表明允许所有的域名来跨域请求它,* 是通配符,没有任何限制
只允许指定域名的跨域请求
Access-Control-Allow-Origin: http://127.0.0.1:5500
-
使用 CORS 跨域的过程
(1) 浏览器发送请求
(2) 后端在响应头中添加 Access-Control-Allow-Origin 头信息
(3) 浏览器接收到响应
(4) 如果是同域下的请求,浏览器不会额外做什么,这次前后端通信就圆满完成了
(5) 如果是跨域请求,浏览器会从响应头中查找是否允许跨域访问
(6) 如果允许跨域,通信圆满完成
(7) 如果没找到或不包含想要跨域的域名,就丢弃响应结果 -
CORS 的兼容性
IE 10 及以上版本的浏览器可以正常使用 CORS
JSONP
-
JSONP 的原理
script 标签跨域不会被浏览器阻止
JSONP 主要就是利用 script 标签,加载跨域文件 -
使用 JSONP 实现跨域
服务器端准备好 JSONP 接口
手动加载 JSONP 接口或动态加载 JSONP 接口
const script = document.createElement('script');
script.src = 'http://www.imooc.com/api/http/jsonp?callback=handleResponse';
document.body.appendChild(script);
// 声明函数
const handleResponse = data => {
console.log(data);
}
XHR 的属性
- responseType 和 response 属性
文本形式的响应内容
responseText 只能在没有设置 responseType 或者 responseType = ‘’ 或者 ‘text’ 的时候才能使用
response 可以替代 responseText,前提是没有兼容性问题
response 和 responseType IE 6~9 不支持,IE 10 开始支持
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 === 403) {
// response
console.log(xhr.response);
}
}
xhr.open('GET', url, true);
// responseType
// xhr.responseType = '';
// xhr.responseType = 'text';
xhr.responseType = 'json';
xhr.send(null);
- timeout 属性
设置请求的超时事件(单位 ms)
IE6~7 不支持,IE8 开始支持
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 === 403) {
console.log(xhr.response);
}
}
xhr.open('GET', url, true);
// timeout
xhr.timeout = 10000;
xhr.send(null);
- withCredentials 属性
指定使用 Ajax 发送请求时是否携带 Cookie
使用 Ajax 发送请求,默认情况下,同域时,会携带 Cookie;跨域时,不会
xhr.withCredentials = true;
最终能否成功跨域携带 Cookie,还要看服务器同不同意
IE6~9 不支持,IE 10 开始支持
XHR 的方法
-
abort()
终止发送请求 -
setRequestHeader()
可以设置请求头信息
xhr.setRequestHeader(头部字段的名称,头部字段的值);
...
xhr.open('POST', url, true);
// xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
username: 'zs'
}));
...
XHR 的事件
- load 事件
响应数据可用时触发
IE6~8 不支持 load 事件
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 === 403) {
console.log(xhr.response);
}
})
xhr.open('GET', url, true);
xhr.send(null);
- error 事件
请求发生错误时触发
IE 10 开始支持
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 === 403) {
console.log(xhr.response);
}
});
xhr.addEventListener('error', () => {
console.log('error');
});
xhr.open('GET', url, true);
xhr.send(null);
- abort 事件
调用 abort() 终止请求时触发
IE10 开始支持
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 === 403) {
console.log(xhr.response);
}
});
xhr.addEventListener('abort', () => {
console.log('abort');
});
xhr.open('GET', url, true);
xhr.send(null);
xhr.abort();
- timout 事件
请求超时后触发
IE 8 开始支持
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 === 403) {
console.log(xhr.response);
}
});
xhr.addEventListener('timeout', () => {
console.log('timeout');
});
xhr.open('GET', url, true);
xhr.timeout = 10000;
xhr.send(null);
xhr.abort();
FormData
- FormData 的基本用法
通过 HTML 表单元素创建 FormData 对象
const fd = new FormData(表单元素);
xhr.send(fd);
通过 append() 方法添加数据
// 也可以步传入表单元素
const fd = new FormData();
fd.append('age', 18);
fd.append('sex', 'male');
IE 10 及以上可以支持
axios
-
axios 是什么
axios 是一个基于 Promise 的 HTTP 库,可以用在浏览器和 node.js 中
第三方 Ajax 库 -
axios 的基本用法
引入 axios
根据 http://www.axios-js.com/zh-cn/docs/ 文档中的说明进行引入
const url = 'https://www.imooc.com/api/http/json/search/suggest?words=js';
axios(url, /* 配置信息 */{
method: 'post',
/* 请求时的头信息 */
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
/* 通过请求头携带的数据 */
params: {
username: 'alex'
}
/* 通过请求体携带的数据 */
data: 'sex=male&age=18',
// timeout: 10
// withCredentials: true
})
.then(response => {
console.log(response);
})
.catch(err => {
console.log(err);
});
如果 data 中传入的为对象,那么 Content-Type 就为 application/json
axios.get(url, /* 配置信息 */{
params: {
username: 'zs'
}
})
.then(response => {
console.log(response);
});
请求中会根据请求体的数据自动添加 Content-Type
axios.post(url, /* 请求体中携带的数据 */{
username: 'zs'
})
.then(response => {
console.log(response);
})
.catch(err => {
console.log(err);
});
创建 axios 实例
import axios from 'axios'
const instance = axios.create({
baseURL: 'https://www.fastmock.site/mock/ae8e9031947a302fed5f92425995aa19/jd',
timeout: 10000
})
const get = (url, param={}) => {
return new Promise((resolve, reject) => {
instance.get(url, { param })
.then(response => {
resolve(response.data)
})
.catch(err => {
reject(err)
})
})
}
const post = (url, data = {}) => {
return new Promise((resolve, reject) => {
instance.post(url, data, {
headers: {
'content-type': 'application/json'
}
})
.then(response => {
resolve(response.data)
})
.catch(err => {
reject(err);
})
})
}
Fetch
-
Fetch 是什么
Fetch 也是前后端通信的一种方式
Fetch 是 Ajax (XMLHttpRequest) 的一种替代方案,它是基于 Promise 的
Ajax 的兼容性比 Fetch 好
Fetch 没有 abort timeout -
Fetch 的基本用法
body: ReadableStream // fetch 提供一种方式读取其中的数据,body只能读一次,读过之后就不让再读了
bodyUsed: false // 读过一次就变成 true 了,就不能再读了
headers: Headers {}
ok: true // 如果为 true ,数据就是可用的,不用再管状态码了
redirected: false
status: 200 // 状态码
statusText: “OK” // 状态码的说明
type: “cors”
url: “https://www.imooc.com/api/http/search/suggest?words=js”
__proto__: Response -
method, body, headers
fetch(url, /* 配置信息 */ {
method: 'post',
body: 'usename=zs&age=18',
// body: JSON.stringify({username: 'zs'}),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
// headers: {
// 'Content-Type': 'application/json'
//}
})
.then(response => {
if (response.ok) {
return response.json(); // 读出数据 会返回 Promise 对象,用 then 获取
// return response.text(); // 如果返回的不是 json 格式
} else {
throw new Error(`HTTP CODE 异常:${response.status}`);
}
})
.then(data => {
console.log(data);
})
// FormData 不需要传 Content-Type
const fd = new FormData();
fd.append('username', 'zs');
fetch(url, /* 配置信息 */ {
method: 'post',
body: fd
})
.then(response => {
if (response.ok) {
return response.json(); // 读出数据 会返回 Promise 对象,用 then 获取
// return response.text(); // 如果返回的不是 json 格式
} else {
throw new Error(`HTTP CODE 异常:${response.status}`);
}
})
.then(data => {
console.log(data);
})
- mode
fetch(url, /* 配置信息 */ {
method: 'post',
body: 'usename=zs&age=18',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
mode: 'cors'; // 跨域资源共享,默认值就是 cors
})
...
- credentials 跨域是否携带 Cookie
fetch(url, /* 配置信息 */ {
method: 'post',
body: 'usename=zs&age=18',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
credentials: 'include'
})
...