Ajax 概述
Asynchronous JavaScript + XML(异步JavaScript和XML),其本身不是一种新技术,而是一个在 2005年被Jesse James Garrett提出的新术语,用来描述一种使用现有技术集合的'新'方法,包括: HTML 或 XHTML, CSS,JavaScript,DOM,XML,XSLT,以及最重要的 XMLHttpRequest;当使用结合了这些技术的AJAX模型以后, 网页应用能够快速地将增量更新呈现在用户界面上,而不需要重载(刷新)整个页面;这使得程序能够更快地回应用户的操作;
尽管X在Ajax中代表XML,但由于JSON的许多优势,比如更加轻量以及作为Javascript的一部分,目前JSON的使用比XML更加普遍;JSON和XML都被用于在Ajax模型中打包信息;
Ajax 优点:
- 最大的一点是页面无刷新,用户的体验非常好
- 使用异步方式与服务器通信,具有更加迅速的响应能力
- 可以把以前一些服务器负担的工作转嫁到客户端,利用客户端闲置的能力来处理,减轻服务器和带宽的负担,节约空间和宽带租用成本。并且减轻服务器的负担, Ajax的原则是"按需取数据",可以最大程度的减少冗余请求,和响应对服务器造成的负担
- 基于标准化的并被广泛支持的技术,不需要下载插件或者小程序
Ajax 缺点:
- Ajax不支持浏览器back按钮
- 安全问题,Ajax暴露了与服务器交互的细节
- 对搜索引擎的支持比较弱
- 破坏了程序的异常机制
Ajax 工作流程
- 网页中发生一个事件(页面加载、按钮点击)
- 由 JavaScript 创建 XMLHttpRequest 对象
- XMLHttpRequest 对象向 web 服务器发送请求
- 服务器处理该请求
- 服务器将响应发送回网页
- 由 JavaScript 读取响应
- 由 JavaScript 执行正确的动作(比如更新页面)
Ajax适用场景
- 表单驱动的交互
- 深层次的树的导航
- 快速的用户与用户间的交流响应
- 类似投票、yes/no等无关痛痒的场景
- 对数据进行过滤和操纵相关数据的场景
- 普通的文本输入提示和自动完成的场景
Ajax不适用场景
- 部分简单的表单
- 搜索
- 基本的导航
- 替换大量的文本
- 对呈现的操纵
XMLHttpRequest API
XMLHttpRequest(XHR)对象用于与服务器交互;通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据;这允许网页在不影响用户操作的情况下,更新页面的局部内容;XMLHttpRequest 在 AJAX 编程中被大量使用;
尽管名称如此,XMLHttpRequest 可以用于获取任何类型的数据,而不仅仅是 XML;它甚至支持 HTTP 以外的协议(包括 file:// 和 FTP),尽管可能受到更多出于安全等原因的限制;
如果您的通信流程需要从服务器端接收事件或消息数据,请考虑通过 EventSource 接口使用 server-sent events;对于全双工的通信, WebSocket 可能是更好的选择;
1. XMLHttpRequest 构造函数
sass
XMLHttpRequest() // 该构造函数用于初始化一个 XMLHttpRequest 实例对象;在调用下列任何其他方法之前,必须先调用该构造函数,或通过其他方式,得到一个实例对象;
2. XMLHttpRequest 属性
sass
XMLHttpRequest.readyState // 只读,返回一个 XMLHttpRequest 代理当前所处的状态
- 0 - UNSENT -- XMLHttpRequest 代理已被创建,但尚未调用 open() 方法
- 1 - OPENED -- open() 方法已经被触发;在这个状态中,可以通过 setRequestHeader() 方法来设置请求的头部,可以调用 send() 方法来发起请求
- 2 - HEADERS_RECEIVED -- send() 方法已经被调用,响应头也已经被接收
- 3 - LOADING -- 响应体部分正在被接收;如果 responseType 属性是"text"或空字符串,responseText 将会在载入的过程中拥有部分响应数据
- 4 - DONE -- 请求操作已经完成;这意味着数据传输已经彻底完成或失败
XMLHttpRequest.status // 只读,返回 XMLHttpRequest 响应中的数字状态码
- 只读属性 XMLHttpRequest.status 返回了XMLHttpRequest 响应中的数字状态码
- status 的值是一个无符号短整型;在请求完成前,status的值为0
- 值得注意的是,如果 XMLHttpRequest 出错,浏览器返回的 status 也为0
XMLHttpRequest.responseText // 只读,一个请求被发送后,从服务器端返回文本
3. XMLHttpRequest 方法
sass
XMLHttpRequest.open(method,url,async,user,password) // 初始化一个请求
- method -- 要使用的HTTP方法
- url -- 一个DOMString表示要向其发送请求的URL
- async -- 一个可选的布尔参数,表示是否异步执行操作,默认为true;如果值为false,send()方法直到收到答复前不会返回;如果true,已完成事务的通知可供事件监听器使用;如果
multipart属性为true则这个必须为true,否则将引发异常
- user -- 可选的用户名用于认证用途;默认为null
- password -- 可选的密码用于认证用途;默认为null
XMLHttpRequest.setRequestHeader('Content-Type','application/x-www-form-urlencoded') // 设置HTTP请求头部的方法;此方法必须在 open() 方法和 send() 之间调用
- 如果没有设置 Accept 头部信息,则会发送带有 "*/*" 的Accept 头部
XMLHttpRequest.send(body) // 用于发送 HTTP 请求;如果是异步请求(默认为异步请求),则此方法会在请求发送后立即返回;如果是同步请求,则此方法直到响应到达后才会返回
- body -- 在XHR请求中要发送的数据体. 可以是 Document,在这种情况下,它在发送之前被序列化
XMLHttpRequest.onreadystatechange = callback // 监听 readyState 属性发生变化触发
axios (网络请求库)
1. axios 方法
javascript
axios.create([config]) // 创建 axios 实例
2. axios 请求配置
javascript
{
// `url` 是用于请求的服务器 URL
url: '/user',
// `method` 是创建请求时使用的方法
method: 'get',// default
// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL;
// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
baseURL: 'https://some-domain.com/api/',
// `transformRequest` 允许在向服务器发送前,修改请求数据
// 只能用在 'PUT','POST' 和 'PATCH' 这几个请求方法
// 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
transformRequest: [function (data,headers) {
// 对 data 进行任意转换处理
return data;
}],
// `transformResponse` 在传递给 then/catch 前,允许修改响应数据
transformResponse: [function (data) {
// 对 data 进行任意转换处理
return data;
}],
// `headers` 是即将被发送的自定义请求头
headers: {'X-Requested-With': 'XMLHttpRequest'},
// `params` 是即将与请求一起发送的 URL 参数
// 必须是一个无格式对象(plain object)或 URLSearchParams 对象
params: {
ID: 12345
},
// `paramsSerializer` 是一个负责 `params` 序列化的函数
// (e.g. https://www.npmjs.com/package/qs,http://api.jquery.com/jquery.param/)
paramsSerializer: function(params) {
return Qs.stringify(params,{arrayFormat: 'brackets'})
},
// `data` 是作为请求主体被发送的数据
// 只适用于这些请求方法 'PUT','POST',和 'PATCH'
// 在没有设置 `transformRequest` 时,必须是以下类型之一:
// - string,plain object,ArrayBuffer,ArrayBufferView,URLSearchParams
// - 浏览器专属:FormData,File,Blob
// - Node 专属: Stream
data: {
firstName: 'Fred'
},
// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
// 如果请求话费了超过 `timeout` 的时间,请求将被中断
timeout: 1000,
// `withCredentials` 表示跨域请求时是否需要使用凭证
withCredentials: false,// default
// `adapter` 允许自定义处理请求,以使测试更轻松
// 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)).
adapter: function (config) {
/* ... */
},
// `auth` 表示应该使用 HTTP 基础验证,并提供凭据
// 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头
auth: {
username: 'janedoe',
password: 's00pers3cret'
},
// `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer','blob','document','json','text','stream'
responseType: 'json',// default
// `responseEncoding` indicates encoding to use for decoding responses
// Note: Ignored for `responseType` of 'stream' or client-side requests
responseEncoding: 'utf8',// default
// `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称
xsrfCookieName: 'XSRF-TOKEN',// default
// `xsrfHeaderName` is the name of the http header that carries the xsrf token value
xsrfHeaderName: 'X-XSRF-TOKEN',// default
// `onUploadProgress` 允许为上传处理进度事件
onUploadProgress: function (progressEvent) {
// Do whatever you want with the native progress event
},
// `onDownloadProgress` 允许为下载处理进度事件
onDownloadProgress: function (progressEvent) {
// 对原生进度事件的处理
},
// `maxContentLength` 定义允许的响应内容的最大尺寸
maxContentLength: 2000,
// `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject promise ;如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte
validateStatus: function (status) {
return status >= 200 && status < 300; // default
},
// `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目
// 如果设置为0,将不会 follow 任何重定向
maxRedirects: 5,// default
// `socketPath` defines a UNIX Socket to be used in node.js.
// e.g. '/var/run/docker.sock' to send requests to the docker daemon.
// Only either `socketPath` or `proxy` can be specified.
// If both are specified,`socketPath` is used.
socketPath: null,// default
// `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理;允许像这样配置选项:
// `keepAlive` 默认没有启用
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// 'proxy' 定义代理服务器的主机名称和端口
// `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据
// 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头;
proxy: {
host: '127.0.0.1',
port: 9000,
auth: {
username: 'mikeymike',
password: 'rapunz3l'
}
},
// `cancelToken` 指定用于取消请求的 cancel token
// (查看后面的 Cancellation 这节了解更多)
cancelToken: new CancelToken(function (cancel) {
})
}
3. axios 响应结构
javascript
{
// `data` 由服务器提供的响应
data: {},
// `status` 来自服务器响应的 HTTP 状态码
status: 200,
// `statusText` 来自服务器响应的 HTTP 状态信息
statusText: 'OK',
// `headers` 服务器响应的头
headers: {},
// `config` 是为请求提供的配置信息
config: {},
// 'request'
// `request` is the request that generated this response
// It is the last ClientRequest instance in node.js (in redirects)
// and an XMLHttpRequest instance the browser
request: {}
}
4. axios 配置默认值
javascript
// 全局的 axios 默认值
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
// 在创建 axios 实例的同时,自定义实例默认值
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
5. axios 拦截器
在请求或响应被
then
或catch
处理前拦截它们
5.1 添加拦截器
javascript
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
},function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
},function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
5.2 移除拦截器
javascript
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
5.3 为自定义 axios 实例添加拦截器
javascript
const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
手写封装 axios 函数
javascript
/**
* ! Ajax 方法封装实现
* * axios.get(url,options) 调用 axios 实现
* * axios.post(url,options) 调用 axios 实现
* * axios.put(url,options) 调用 axios 实现
* * axios.delete(url,options) 调用 axios 实现
*/
/**
* ! Ajax 封装
*
* @param {*} { method<请求方式>,url<请求地址>,params<请求参数>,data<请求体> }
* @return {*} promise 对象
*/
function axios({ method,url,params,data }) {
// method 转换大写
method = method.toUpperCase()
// 返回 promise 对象
return new Promise((resolve,reject) => {
// 请求四步走
// 1.创建对象
const xhr = new XMLHttpRequest()
// 2.初始化
// 2.1 处理 params 对象 X=XXXX&X=XXX
let str = ''
for (const key in params) {
str += `${key}=${params[key]}&`
}
str = str.slice(0,-1)
xhr.open(method,url + '?' + str)
// 3.发送
if (method === 'POST' || method === 'PUT' || method === 'DELETE') {
// Content-type mime类型设置
xhr.setRequestHeader('Content-type','application/json')
// 设置请求体
xhr.send(JSON.stringify(data))
} else {
xhr.send()
}
// 响应结果格式设置为 JSON 创建的 JS 对象
xhr.responseType = 'json'
// 4.处理结果
// 现代写法(指定多个回调)
xhr.addEventListener("load",()=>{})
// 原有写法
xhr.onreadystatechange = function () {
// 判断 XMLHttpRequest 代理当前所处的状态 4 === 下载操作已完成;
if (xhr.readyState === 4) {
// 判断响应状态码
if (xhr.status >= 200 && xhr.status < 300) {
// 成功状态
resolve({
status: xhr.status,
message: xhr.statusText,
body: xhr.response,
})
} else {
reject(new Error('请求失败,失败的状态码为:' + xhr.status))
}
}
}
})
}
axios.get = function (url,options='') {
// 发起 Ajax 请求
return axios(Object.assign(options,{ method: 'GET',url: url }))
}
axios.post = function (url,options='') {
// 发起 Ajax 请求
return axios(Object.assign(options,{ method: 'POST',url: url }))
}
axios.put = function (url,options='') {
// 发起 Ajax 请求
return axios(Object.assign(options,{ method: 'PUT',url: url }))
}
axios.delete = function (url,options='') {
// 发起 Ajax 请求
return axios(Object.assign(options,{ method: 'DELETE',url: url }))
}