现代浏览器都通过 XMLHttpRequest 构造函数原生支持XHR对象

  1. let xhr = new XMLHttpRequest();

对于 IE7 以前

  1. var xhr;
  2. if(window.XMLHttpRequest){
  3. xhr = new XMLHttpRequest(); // ie7+ 标准化
  4. }else{
  5. xhr = new ActiveXObject('Microsoft.XMLHTTP') ;
  6. }

使用 XHR

open()

  • 参数
    1. 请求类型
      • GET 简单请求
      • POST 复杂请求 除GET之外
        • GET 与 POST 差异
          1. POST 更安全
          2. POST 发送数据量大,GET 有 url 长度限制 (在规范中 GET 是没有长度限制,只是在浏览器的实现中有限制)
            • IE 2083Byte / Firefox 65536Byte / Chrome 8182Byte / Safari 80000Byte / Opera 190000Byte
          3. POST 能发送更多的数据类型 各种类型的文件
          4. GET 只能发送 ASCII 字符
            1. encodeURI() / decodeURI() / encodeURIComponent() / decodeURIComponent() (URI 中具有特殊含义的 ASCII 标点符号进行转义)
        • HEAD OPTIONS PUT DELETE CONNECT TRACT 为什么不用?
          • 因为前后端分离,不是混编。如果使用会暴露行为的目的不安全。
          • 现在前端不直接操作后端的数据(由后端处理),前端没有必要作一个请求方式。
    2. 请求 URL
    3. 是否异步的布尔值
  • 注意
    • URL是相对于代码所在页面,也可以使用绝对 URL
    • 调用 open() 不会实际发送请求,只为发送请求做好准备
    • 只能访问同源URL

send()

  • 参数 请求体发送的数据,不需要发送请求体必须传 null

等待响应后 XHR 对象的属性被填充上数据

  • responseText 作为响应体返回的文本
  • responseXML 如果响应内容类型是 “text/xml” 或 “application/xml”,就是包含响应数据的 XML DOM 文档
  • status 响应的 HTTP 状态
    • 收到响应要先检查status属性以确保响应成功(2xx 或者 304 直接拿取缓存)
  • statusText 响应的 HTTP 状态描述
  • readyStatus 表示当前处在请求/响应的过程在哪个阶段
    • 0 未初始化(Uninitialized)尚未调用 open() 方法
    • 1 已打开(Open)已经调用 open() 方法,尚未调用 send() 方法
    • 2 已发送(Sent)已经调用 send() 方法,尚未收到响应
    • 3 接收中(Receiveing)已经收到部分响应
    • 4 完成(Complete)已经收到所有响应,可以使用
  • readystatechange 事件 每次当 readyState 从一个值变成另一个值时触发
  • abort() 方法 取消异步请求

    • 调用后 XHR 对象停止触发事件,阻止访问对象上任何与响应相关的属性
    • 中断请求后,应该取消对 XHR 对象的引用。由于内存问题,不推荐重用 XHR 对象

      HTTP 头部

      默认XHR请求发送以下头部字段
  • Accept:浏览器可以处理的内容类型。

  • Accept-Charset:浏览器可以显示的字符集。
  • Accept-Encoding:浏览器可以处理的压缩编码类型。
  • Accept-Language:浏览器使用的语言。
  • Connection:浏览器与服务器的连接类型。
  • Cookie:页面中设置的Cookie。
  • Host:发送请求的页面所在的域。
  • Referer:发送请求的页面的URI。注意,这个字段在 HTTP 规范中就拼错了,所以考虑到兼容性也必须将错就错。(正确的拼写应该是 Referrer。)
  • User-Agent:浏览器的用户代理字符串。

setRequestHeader()

  • 为XHR对象设置响应头部
  • 在 open() 之后 send(),调用 setRequestHeader(key,value)

getResponseHeader()

  • 参数 key
  • 从 XHR 对象获取响应头部

getAllResponseHeaders()

  • 返回包含所有响应头部字符串
    1. Date: Sun, 14 Nov 2004 18:04:03 GMT
    2. Server: Apache/1.3.29 (Unix)
    3. Vary: Accept
    4. X-Powered-By: PHP/4.3.8
    5. Connection: close
    6. Content-Type: text/html; charset=iso-8859-1

    GET 请求

    在 URL 后添加查询字符串参数。查询字符串每个名和值都使用 encodeURIComponent() 编码,所有键/值对以&分隔。
    1. function addURLParam(url, name, value) {
    2. url += (url.indexOf("?") == -1 ? "?" : "&");
    3. url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
    4. return url;
    5. }

    POST 请求

    XHR 模拟表单提交
  1. ContentType 的头部设置为提交表单使用的内容类型: “application/x-www-formurlencoded”
    • xhr.setRequestHeader('ContentType', 'application/x-www-formurlencoded'
  2. 创建对应格式作请求体

    • 字符串 ‘param1=a&param2=b’
      • 把 form 标签下的序列化为格式字符串 ```javascript function serialize(form) { let parts = []; let optValue;

    for (let field of form.elements) { switch(field.type) { case “select-one”: case “select-multiple”:

    1. if (field.name.length) {
    2. for (let option of field.options) {
    3. if (option.selected) {
    4. if (option.hasAttribute){
    5. optValue = (option.hasAttribute("value") ?
    6. option.value : option.text);
    7. } else {
    8. optValue = (option.attributes["value"].specified ?
    9. option.value : option.text);
    10. }
    11. parts.push(encodeURIComponent(field.name)} + "=" +
    12. encodeURIComponent(optValue));
    13. }
    14. }
    15. }
    16. break;

    case undefined: // 字段集 case “file”: // 文件输入 case “submit”: // 提交按钮 case “reset”: // 重置按钮 case “button”: // 自定义按钮

    1. break;

    case “radio”: // 单选按钮 case “checkbox”: // 复选框

    1. if (!field.checked) {
    2. break;
    3. }

    default:

    1. // 不包含没有名字的表单字段
    2. if (field.name.length) {
    3. parts.push(`${encodeURIComponent(field.name)}=` +
    4. `${encodeURIComponent(field.value)}`);
    5. }

    } return parts.join(“&”); }

    1. - FormData 类型 便于表单序列化
    2. ```javascript
    3. let data = new FormData(document.forms[0]);
    4. data.append("name", "Nicholas");
    • 不再需要给 XHR 显式设置请求头部,XHR 对于 FormData 实例能自动配置相应头部
      • qs.stringify()
  3. 发送请求体 xhr.send('param1=a&param2=b');

    XMLHttpRequest Level 2

  • FormData 类型
  • 超时 xhr.timeout
    • 触发事件 timeout
  • overrideMimeType() 方法,重写 XHR 响应 MINE 类型

    load 事件

    load 事件替代 readystatechange 事件, 这样就不用检查 readyState 属性 了。

  • 在响应接收完成后立即触发

  • event.target == xhr

不过,并不是所有浏览器都实现了这个事件的 event 对象。考虑 到跨浏览器兼容,还是需要像下面这样使用 XHR 对象变量:

  1. let xhr = new XMLHttpRequest();
  2. xhr.onload = function() {
  3. if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
  4. alert(xhr.responseText);
  5. } else {
  6. alert("Request was unsuccessful: " + xhr.status);
  7. }
  8. };
  9. xhr.open("get", "altevents.php", true);
  10. xhr.send(null);

progress

事件

  • loadstart:在接收到响应的第一个字节时触发。
  • progress:在接收响应期间反复触发。
    • event 对象
      • targetXHR 对象
      • lengthComputable 布尔值,进度信息是否可能
      • position 接收到的字节数
      • totalSize 响应的 ContentLength 头部定义的总字节数
  • error:在请求出错时触发。
  • abort:在调用 abort() 终止连接时触发。
  • load:在成功接收完响应时触发。
  • loadend:在通信完成时,且在 error、abort 或 load 之后触发。
    1. let xhr = new XMLHttpRequest();
    2. xhr.onload = function(event) {
    3. if ((xhr.status >= 200 && xhr.status < 300) ||
    4. xhr.status == 304) {
    5. alert(xhr.responseText);
    6. } else {
    7. alert("Request was unsuccessful: " + xhr.status);
    8. }
    9. };
    10. xhr.onprogress = function(event) { // 为了保证正确执行,必须在调用 open()之前添加 onprogress 事件处理程序。
    11. let divStatus = document.getElementById("status");
    12. if (event.lengthComputable) {
    13. divStatus.innerHTML = "Received " + event.position + " of " +
    14. event.totalSize +
    15. " bytes";
    16. }
    17. };
    18. xhr.open("get", "altevents.php", true);
    19. xhr.send(null);