XMLHttpRequest 的简单记录

80 阅读3分钟

XMLHttpRequest 的简单记录。

写过无数次的 $.ajax ,然而jQuery 没落了。当前比较流行的是 axios 库,和 $.ajax 同是基于 XMLHttpRequest,本章节简单记录 XMLHttpRequest 和相关有用的代码 ,以便用时方便查找。也许不久后,XMLHttpRequest 也将过时,被 fetch 取代。至于 ajax / axios / fetch 不多赘述,相关的 api 比较类似并且很好查。

一 XMLHttpRequest

XMLHttpRequest ,ajax (Asynchronous JavaScript and XML) 发出 HTTP 请求、进行浏览器和服务器通信的原生对象。

/* 1. 创建实例 */
var xhr = new XMLHttpRequest();
/* 2. 监听请求是否成功 */
xhr.onload = function() {
    console.log('请求成功');
}
/**
* 3. 发出 HTTP 请求: open 启动请求; send 发送请求。
*  open 参数:open(method,url,async)
*   method: 请求方法,GET, POST 等       
*   url:发送请求的地址
*   async:是否异步,true 表示异步,false 表示同步。
*/
// GET 请求参数直接写在url后面,如 http://localhost/hello?name=jack&age=20
xhr.open('GET', 'http://localhost/hello?name=jack&age=20', true);
xhr.send();

// POST 需要向请求添加 http 头: setRequestHeader(header,value), header: 规定头的名称,value: 规定头的值
// 请求参数要写在 send() 方法内,send() 方法接收一个 String 类型的参数 
xhr.open('POST', 'http://localhost/hello', true);
// 一般格式参数
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded")
xhr.send('name=jack&age=20');
// json 格式参数, 通过 JSON.stringify() 转成字符串
xhr.setRequestHeader("Content-type","application/json")
xhr.send(JSON.stringify({"name":"jack","age":20}));

/**
* 4. 响应 
* 反应响应状态的三个属性:
*   readyState:0-请求未初始化;1-已经调用open;2-发送,已经调用send;3-请求处理中;4-请求已完成,且响应已就绪
*   onreadystatechange:事件,每当 readyState 改变时,就会调用该函数。
*   status:200-成功;404-未找到地址
* 响应的内容:
*   responseText: 返回字符串形式的内容
*   responseXML:返回 xml 形式的内容
*/
xhr.onreadystatechange=function() {
  if (xhr.readyState==4 && xmlhttp.status==200) {
        console.log(xhr.responseText);
    }
}

/* 终止请求 onabort ie10+ */
xhr.abort();
// 终止请求后可以触发的事件
xhr.onabort = funciton(){}

/* 超时 超过时间后没有返回,请求会自动终止, 触发 ontimeout 事件。ontimeout ie10+。*/
xhr.timeout = 1000;
xhr.ontimeout = function(){}

虽然 MDN 给出了 timeout 在各浏览器中的兼容性,但《javascript权威指南》和《javascript高级程序设计》对它目前的兼容性很不乐观,以下是权威指南给的一段自定义实现超时的代码:

function timedGetText(url, timeout, callback){
    var request = new XMLHttpRequest();
    var timedout = false;

    var timer = setTimeout(function(){
        timedout = true;
        request.abort();
    }, timeout);

    request.open('GET', url);
    request.onreadystatechange = function(){
        if(!request.readyState !== 4) return;
        if(timedout) return;
        clearTimeout(timer);
        if(request.status === 200){
            callback(request.responseText);
        }
    };
    request.send(null);
}

二 axios

axios

如下是一段封装好的 axios,并不是十分好,不过也许方便后续使用。如需更改,仍要参考官网,官网很详尽。

import axios from 'axios';
import Qs from 'qs';
// 请求失败报错列表
const errorStatusMap = new Map([
  [400, '参数不合法'],
  [401, '未授权,请登录'],
  [403, '拒绝访问'],
  [404, '资源不存在'],
  [408, '请求超时'],
  [500, '服务器内部错误'],
  [501, '服务未实现'],
  [502, '网关错误'],
  [503, '服务不可用'],
  [504, '网关超时'],
  [505, 'HTTP版本不受支持']
]);
// create an axios instance
export const service = axios.create({
  baseURL: '/',
  // 如果请求超过 `timeout` 的时间,请求将被中断
  timeout: 1000,
  transformRequest(data, headers) {
    if (headers.tp === '1') {
      return Qs.stringify(data, {
        allowDots: true,
        arrayFormat: 'indices'
      });
    }
    if (headers['Content-Type'] !== 'multipart/form-data') {
      return Qs.stringify(data, {
        allowDots: true,
        arrayFormat: 'brackets'
      });
    }
    return data;
  },
  // 负责params 序列化函数
  paramsSerializer(params) {
    return Qs.stringify(params);
  }
});

// 引入本地json文件
export const getJson = (url) =>
  new Promise((resolve, reject) => {
    axios({
      method: 'get',
      url,
      dataType: 'json',
      crossDomain: true,
      cache: false
    })
      .then((res) => {
        resolve(res);
      })
      .catch((error) => {
        reject(error);
      });
  });

// 请求拦截
service.interceptors.request.use(
  (config) => config,
  (error) => (console.log(error))
);
// 响应拦截
service.interceptors.response.use(
  (response) => {
    if (response.status === 200) {
      const { data } = response;
      // dosomething
      return data
    }
    return Promise.reject(response);
  },
  (error) => {
    if (error && error.response) {
      error.message = errorStatusMap.get(error.response.status) ? errorStatusMap.get(error.response.status) : error;
    } else if (error && error.request) {
      if (error.request.readyState === 4 && error.request.status === 0) {
        error.message = '接口响应超时';
      }
    }
    return Promise.reject(error.message);
  }
);
const request = {
  post(url, data, config) {
    return service.post(url, data, config);
  },
  get(url, params, config) {
    return service.get(url, { params, config });
  },
  getJson(url) {
    return getJson(url);
  },
  upload(url, data, config) {
    return service.post(url, data, config);
  }
};
export default request;

三 Fetch

Fetch