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 构造函数
XMLHttpRequest() // 该构造函数用于初始化一个 XMLHttpRequest 实例对象;在调用下列任何其他方法之前,必须先调用该构造函数,或通过其他方式,得到一个实例对象;
2. XMLHttpRequest 属性
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 方法
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 方法
axios.create([config]) // 创建 axios 实例
2. axios 请求配置
{ // `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 响应结构
{ // `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 配置默认值
// 全局的 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 添加拦截器
// 添加请求拦截器 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 移除拦截器
const myInterceptor = axios.interceptors.request.use(function () {/*...*/}); axios.interceptors.request.eject(myInterceptor);
5.3 为自定义 axios 实例添加拦截器
const instance = axios.create(); instance.interceptors.request.use(function () {/*...*/});
手写封装 axios 函数
/** * ! 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 })) }