4 Ajax

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 优点:

  1. 最大的一点是页面无刷新,用户的体验非常好
  2. 使用异步方式与服务器通信,具有更加迅速的响应能力
  3. 可以把以前一些服务器负担的工作转嫁到客户端,利用客户端闲置的能力来处理,减轻服务器和带宽的负担,节约空间和宽带租用成本。并且减轻服务器的负担, Ajax的原则是“按需取数据”,可以最大程度的减少冗余请求,和响应对服务器造成的负担
  4. 基于标准化的并被广泛支持的技术,不需要下载插件或者小程序

Ajax 缺点:

  1. Ajax不支持浏览器back按钮
  2. 安全问题,Ajax暴露了与服务器交互的细节
  3. 对搜索引擎的支持比较弱
  4. 破坏了程序的异常机制

Ajax 工作流程


  1. 网页中发生一个事件(页面加载、按钮点击)
  2. 由 JavaScript 创建 XMLHttpRequest 对象
  3. XMLHttpRequest 对象向 web 服务器发送请求
  4. 服务器处理该请求
  5. 服务器将响应发送回网页
  6. 由 JavaScript 读取响应
  7. 由 JavaScript 执行正确的动作(比如更新页面)

Ajax适用场景

  1. 表单驱动的交互
  2. 深层次的树的导航
  3. 快速的用户与用户间的交流响应
  4. 类似投票、yes/no等无关痛痒的场景
  5. 对数据进行过滤和操纵相关数据的场景
  6. 普通的文本输入提示和自动完成的场景

Ajax不适用场景

  1. 部分简单的表单
  2. 搜索
  3. 基本的导航
  4. 替换大量的文本
  5. 对呈现的操纵

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 拦截器

在请求或响应被 thencatch 处理前拦截它们

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 }))
}
  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

taciturn丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值