AJAX基础知识:核心原理是基于XMLHttpRequest实现前后端数据通信的
面试题:Ajax中有多少个方法?
私有属性
可以监听的事件
+ onabort 请求被中断触发
+ onreadystatechange 监听Ajax的状态改变(根据不同的状态处理不同的事情)
+ ontimeout 请求超时后触发
+ upload.onprogress 监听文件上传或者下载的进度
常规属性
+ readyState 记录ajax状态
+ status/statusText 服务器返回的HTTP状态码及其描述
+ timeout 设置超时时间(MS),默认0代表不设置:如果设置了超时时间,在这个期间内,如果请求没有结束,则自动中断,触发ontimeout事件
+ withCredentials 在“跨域”请求中,设置是否允许携带资源凭证(例如:cookie),默认false
+ response 存储服务器返回的响应主体信息(不论啥格式)
+ responseText 存储格式为字符串的响应主体信息
+ responseXML 存储格式为XML的响应主体信息
+ ...
公共方法
+ open() 打开请求连接(在发送请求之前进行一些配置)
+ send([body]) 发送请求,并且基于请求主体把信息传递给服务器
+ setRequestHeader([key],[value]) 设置请求头信息{传递的值不能有中文,如果有需要编码}
+ 转码的三种方式
+ escape
+ encodeURI
+ encodeURIComponent
+ overrideMimeType() 重写MIME类型
+ getAllResponseHeaders() / getResponseHeader([key]) 获取所有(某一个)响应头信息
+ abort() 中断当前请求
----
代表Ajax状态(xhr.readyState)的五个属性
+ UNSENT: 0 未发送(最开始创建出XHR实例的初始状态)
+ OPENED: 1 已经执行了open这个方法
+ HEADERS_RECEIVED: 2 请求已经发送,并且获取到了响应头信息
+ LOADING: 3 响应主体信息正在返回中
+ DONE: 4 响应主体信息已经返回(当前Ajax请求结束)
Ajax核心操作:
@1 ajax:async javascript and xml 「了解」
+ async javascript:不仅仅是异步请求,更主要的是“局部刷新”
+ xml:很早很早以前,Ajax从服务器获取的数据格式一般都是XML格式的,只不过目前我们都是基于体积更小、操作更方便的JSON格式进行传输!!
@2 请求方式:GET系列 & POST系列 GET系列:GET/HEAD/DELETE/OPTIONS POST系列:POST/PUT/PATCH ---
不论GET还是POST,客户端都可以在发请求的时候,把信息传递给服务器,服务器也可以把信息返回客户端;
客户端->服务器
+ URL问号传参 '/user/list?xxx=xxx&xxx=xxx'
+ 设置请求头 xhr.setRequestHeader(xxx,xxx);
+ 设置请求主体 xhr.send(xxx);
服务器->客户端
+ 设置响应头
+ 设置响应主体 「响应头信息会比响应主体先发返回」
---
约定俗成的规范:GET系列请求,一般都是基于“URL问号传参”把信息传递给服务器;而POST系列请求,一般是基于请求主体把信息传递给服务器;两种方式都可以设置请求头信息!!
+ 传递给服务器信息的大小
+ GET是基于URL传参,而浏览器对于URL的长度有限制(IE:2KB、谷歌:8KB、火狐:7KB...),所以GET传递给服务器的信息要少!!
+ POST是基于请求主体传递信息,理论上是没有任何长度限制的「实际开发中,我们自己做限制」
+ 安全方面
+ 互联网面前,人人都在“裸奔”,没有绝对的安全
+ POST比GET相对安全一些:因为有一种很好实现的“黑客”技术--URL劫持,而GET是URL传参,一旦被劫持,则信息泄露;而请求主体的信息不容易被劫持!
+ 缓存问题
+ 还是因为GET是URL传参,如果多次请求:地址+传递参数值 都完全一致,浏览器可能会帮我们获取上一次缓存中的信息,导致无法实时获取最新的信息!
解决:保证每一次请求传递的参数值不完全一致即可
xhr.open('GET',`/user/list?xxx=xxx&_=${+new Date()}`);
---
基于请求主体传递给后台的内容有“格式要求”:每一种格式都有相关的描述,我们称之为MIME类型
+ JSON格式的字符串 MIME:application/json
'{"name":"xxx","age":25,...}'
+ URLENCODED格式字符串 MIME:application/x-www-form-urlencoded
'xxx=xxx&xxx=xxx&...'
+ FORM-DATA格式对象 MIME:multipart/form-data {一般用于文件上传}
let fm=new FormData();
fm.append('name','xxx');
fm.append('file',...);
xhr.send(fm);
+ 普通格式字符串 MIME:text/plain
+ 传递Buffer(进制)格式的数据
+ ...
---
如果传递的是普通对象,浏览器也会默认转换为“[object Object]”传递给服务器!!
当我们基于xhr.send请求主体,发送信息给服务器的时候,根据我们传递的数据格式,需要手动设置请求头:xhr.setRequestHeader('Content-Type',对应的MIME类型)
@3 设置请求头的操作必须在:OPEND之后和SEND之前;而且设置请求头的信息不能出现中文,如果需要传递中文,则需要编码「encodeURIComponent / encodeURI」
@4 xhr.status记录服务器返回的HTTP响应状态码:不同的状态码描述了请求成功或者失败 + xhr.status:HTTP响应状态码 (服务器基于不同的状态码告知客户端相应的结果)
+ 以2开始的基本上都是成功
+ 200 Ok 标准成功
+ 206 Partial Content 断点续传
+ 以3开始的虽然也获取到数据了,但是中间会经历一些特殊的处理
+ 301 Moved Permanently 永久转移(永久重定向)===>域名迁移
+ 302 (307) Move Temporarily 临时转移(临时重定向)===>服务器负载均衡
+ 304 Not Modified 服务器资源未更新(协商缓存)
+ 以4开始的一般都是客户端错误
+ 400 Bad Request 参数错误
+ 401 Unauthorized 权限有问题
+ 403 Forbidden 服务器拒绝你的请求,但是为啥不告诉你,因为原因很多
+ 404 Not Found 地址错误
+ 405 Method Not Allowed 请求的方式不被允许
+ 408 Request Timeout 请求超时
+ 以5开始的一般都是服务器错误
+ 500 Internal Server Error 未知服务器错误
+ 502 Bad Gateway 网管或者代理服务器出现了问题
+ 503 Service Unavailable 超负荷
let xhr = new XMLHttpRequest;
xhr.open('GET', './package.json');
xhr.timeout = 10000;
xhr.withCredentials = true;
xhr.setRequestHeader('name', encodeURIComponent('珠峰培训'));
xhr.onreadystatechange = () => {
let { readyState, status } = xhr;
if (!/^(2|3)\d{2}$/.test(status)) {
// 状态码出现问题:本次请求失败
return;
}
// 服务器正常返回信息了
if (readyState === 2) {
// 响应头信息已经有了:获取的服务器时间是格林尼治时间,我们需要变为北京时间
let serverTime = xhr.getResponseHeader('date');
console.log('服务器时间:', new Date(serverTime));
}
if (readyState === 4) {
// 响应主体信息已经有了,常见的响应主体信息的格式
// + JSON字符串「最常用的」
// + XML格式的数据 xhr.responseXML
// + Buffer格式的数据
// + ...
let data = JSON.parse(xhr.responseText);
console.log('响应主体:', data);
}
};
xhr.onerror = () => {
// 进入这里一般是网络问题
};
xhr.send();
真实项目中,我们应用的是把Ajax进行封装的插件/库
- JQ :基于回调函数方式管理
- Axios :基于Promise管理
$.ajax({
url: './package.json',
method: 'GET',
dataType: 'json', //把从服务器获取的响应主体信息,转换为指定的格式
cache: true, //GET系列请求是否设置缓存 false去掉缓存
data: { //GET系列请求,会把对象中的信息以URL问号传参传递给服务器;POST系列请求,会作为请求主体传递给服务器(会把对象默认变为URLENCODED字符串处理)!
name: 'xxx',
age: 25
},
success(value) {
console.log('成功:', value);
},
error(reason) {
// HTTP状态码不是2开头、网络出问题、请求中断/超时...
console.log('失败:', reason);
}
});