zoukankan      html  css  js  c++  java
  • AJAX-XMLHttpRequest

    一. AJAX是什么?

    AJAX是js脚本向服务器发起http通信的统称。

    总的来说,ajax就是js通过XMLHttpRequest创建实例,发起请求,接受请求,更新页数据的过程。

    二.XMLHttpRequest

    1.什么是XMLHttpRequest?

    XMLHttpRequest是一个位于Window对象上的一个原生的构造函数。

    它是ajax通信的主要接口,用于浏览器和服务器之间通信。

    通过它生成的实例对象,可以用于发起http请求:

    const xhr = new XMLHttpRequest();

    由于位于Window对象,所以实例化的xhr对象其实就是一个浏览器内置的对象。

    它提供了对http协议的完全的访问,用于JS进行http请求和http响应。

    2.兼容性

    几乎所有的主流浏览器都支持,IE需要通过下面的办法兼容

     new ActiveXObject("Microsoft.XMLHTTP")

    3.发展历史

    XMLHttpRequest有两个阶段,一个是Level1,一个是Leve2

    level1的缺点:

    • 受同源策略(Same Origin Policy)影响, 不能发送跨域请求
    • 不能发送二进制(音频,视频,图片等)文件,只能发送文本
    • 发送和接收数据时,没有实时进度信息,只能判断是否完成

    level2解决了以上缺点,并添加了新功能:

    • 只要服务器允许,可以进行跨域访问
    • 可以发送和获取二进制数据(音频,视频,图片等都是二进制文件)
    • 可以获取请求发送数据的实时进度信息
    • 新增FormData数据,可以发送表单数据(multipart/formdata)
    • 可以设置过时时间timeout

    4.只读属性

    1.readyState --HTTP 请求的状态.

    从对象实例化为0开始到结束为4,依次递增。

    状态 名称 描述
    0 UNSENT 初始化。new了实例或者已经被abort()方法重置
    1 OPENED 调用了open方法,但是还未调用send方法。请求还未发送。
    2 HEADERS_RECEIVED send发送成功。并且接收到服务器返回的请求头和状态码
    3 LOADING 响应头已经接收。响应体开始接收,未完成。
    4 DONE 响应接收完成。

    每次状态改变都会触发onreadystatechange事件。

     LOADING状态可能会触发多次,因为每接收一个数据包就会触发一次。

    2.status--http请求响应中~的状态码

    进入响应前和响应失败都是0;响应中如果未特殊指定,都为200。

    let xhr = null;
    if (window.XMLHttpRequest) {// code for Firefox, Chrome, etc.
        xhr = new XMLHttpRequest();
    } else if (window.ActiveXObject) {// code for IE
        xhr = new ActiveXObject("Microsoft.XMLHTTP");
    }
    console.log('UNSENT-->',xhr.readyState,'-->', xhr.status,'-->',xhr.statusText);
    if (xhr != null) {
        let data = null
        xhr.open('GET','./1.jpeg', true);
        console.log('OPENED-->',xhr.readyState,'-->', xhr.status,'-->',xhr.statusText);
        xhr.send(data);    
    }
    xhr.onreadystatechange = function() { // 只有在readyState >=3 的时候,才能获取正确的结果。
        console.log('状态变化-->',xhr.readyState,'-->',xhr.status,'-->',xhr.statusText)
    }
    xhr.onprogress = function () {
        console.log('LOADING',xhr.readyState,'-->', xhr.status,'-->',xhr.statusText);
    };
    xhr.onload = function () {
        console.log('DONE',xhr.readyState,'-->', xhr.status,'-->',xhr.statusText);
    };
    // 运行结果如下:
    /*
    UNSENT-->0 -->0 -->""
    OPEND-->1-->0-->""
    状态变化-->1->0-->""
    状态变化-->2-->200-->"OK" //headers_received
    状态变化-->3-->200-->"OK" //loading
    LOADING-->3-->200-->"OK" 
    LOADING-->4-->200-->"OK"
    状态变化-->4-->200-->"OK" //done
    DONE-->4-->200-->"OK"
    */

    3. statusText -- http响应中~的状态名称

    例如:xhr.statusText --- OK 

    4. response--返回响应

    如果responseType的类型是""或者"text",那么LOADING状态时,会接收到传递的部分数据。

    5. responseText

    从服务器返回的字符串;当readyState为4时,取到完整的字符串。为3时,可能返回部分数据。

    6. responseXML

    从服务器返回的XML/HTML文档;要求返回的Content-Type: text/xml 或者application/xml。

    该属性生效的前提是:

    xhr.responseType = "document";

    如果仍不符合要求:

    xhr.overrideMimeType('text/xml');

    7.responseURL

    返回实际返回数据(跳转则为跳转后的网址)的服务器的地址;如果有锚点(fragment),会自动剥离锚点。

    5.可写属性

    1.responseType --- 指定服务器应该返回的数据类型

    • "": 默认。 返回字符串,等同于"text"类型。
    • "text": 返回字符串。
    • "arraybuffer": 返回ArrayBuffer类型的数据(二进制数组)。
    • "blob": 返回Blob数据,二进制对象,如图片。
    • "document": 返回Document对象,文档对象,XML或者HTML文档。
    • "json": 返回JSON对象。
    xhr.responseType = 'json';
    // 如果设置为json,浏览器会自动调用JSON.parse()方法;
    // 即通过xhr.response返回的是一个JSON对象

    如果responstType指定的数据,服务器无法返回,可以通过xhr.overrideMimeType()来

    覆盖服务器返回的数据类型。客户端根据该方法的参数解析

    // 该方法必须在send()方法之前调用
    xhr.overrideMimeType('text/plain');

    2.timeout--设置请求超时时间

    默认0,表示不设置请求超时。

    其他数值,单位为ms, 规定时间后触发ontimeout事件。

    3.withCredentials--携带验证信息

    默认false; 该属性只跨域请求时需要设置。

    同域请求时,浏览器会自动将cookie添加到请求头中,但是跨域请求不会。

    因为CORS规定,跨域时,不允许携带任何认证信息,除非withCredentials=true;

    首先,为了能够跨域,服务器端需要设置

    Access-Control-Allow-Origin: *// 或者具体的域名

    如果请求需要认证信息,浏览器端需要设置:

    xhr.withCredentials = true

    服务器端需要设置

    Access-Control-Allow-Origin: //具体的origin,一定不能设置成*
    Access-Control-Allow-Credentials: true

    6.方法

    1.open(method, url [, async, username, password])方法

    初始化请求参数

    method: 请求方式主要有GET、POST、PUT、DELETE,也可以是HEAD(请求资源的头部信息,和GET返回的头部一样)---CORS安全

    url: 请求路由

    async: 默认true,异步请求。为false时,同步, 已被废弃deprecated

    基本都用异步请求。同步请求几乎不用,一是因为会出现阻塞,网页挂起的情况;二是不能使用timeout,不能进行跨域,也没有进度信息。

    const xhr = new XMLHttpRequest();
    xhr.open("POST", url, true); // 异步
    xhr.send();
    // readyState === 1 异步请求send立即返回
    
    const xhr = new XMLHttpRequest();
    xhr.open("POST", url, false); // 同步
    xhr.send();
    // readyState === 4 同步等所有的进程结束再返回

    username,password: 认证权限

    2. setRequestHeader(name, value)

    只能在open和send之间调用。既可以设置系统默认的一些头部信息(如ContentType),也可以设置自定义的头部信息(‘X-USER’)。

    一旦设置,就无法撤销。设置同样的name,也是append,而不会覆盖。

    var client = new XMLHttpRequest();
    client.open('GET', 'demo.cgi');
    client.setRequestHeader('X-Test', 'one'); // 自定义请求头
    client.setRequestHeader('X-Test', 'two');  // 自定义请求头
    client.send();
    // X-TEST: one, two

    name: 请求头的名称。忽略大小写。

    有些请求头只能由浏览器控制,用户不能操作。否则  Refused to set unsafe header "..."

    `Accept-Charset`
    `Accept-Encoding`
    `Access-Control-Request-Headers`
    `Access-Control-Request-Method`
    `Connection`
    `Content-Length`
    `Cookie`
    `Cookie2`
    `Date`
    `DNT`
    `Expect`
    `Host`
    `Keep-Alive`
    `Origin`
    `Referer`
    `TE`
    `Trailer`
    `Transfer-Encoding`
    `Upgrade`
    `Via`

    用户可以操作的请求头有:

    Accept: 通过设置Accept通知服务器客户端可以接受的数据类型。

    Content-Type: 设置发送的数据类型,即send(body)中请求体的类型。以下全部为POST请求

          GET方法设置这些请求头无效

    • "multipart/form-data; boundry=something": 当传递FormData类型时,默认是该类型。

          // 示例: multipart/form-data; boundary=----WebKitFormBoundary2OgAPgMEOp8S1XFR

          相当于表单设置了enctype属性,<form enctype="multipart/form-data"></form> 

          如果是GET方法,enctype的值被忽略

    ...
    data = new FormData();
    data.append('name', 'lyra'); // append方法的第一个参数是控件名;第二个参数是值
    data.append('age',18);
    xhr.send(data); 
    // 还可以从网页中获取表单的值
    <form id="form">
       <input type='text' name="age" value="" /><!--必须有name,用于作为参数名-->
    </form>
    const formData = document.querySelector('#form'); // formData是整个form表单对应的元素 data = new FormData(formData); data.append('name','lyra'); xhr.send(data); // 还可以上传文件等二进制文件 <body> <button onclick="loadJSONDoc()">Get JSON</button> <form id="form"> <label for="image">上传图片</label> <input id="file" type='file' name="image" accept="image/png,image/jpeg" multiple /> </form> <script> var xhr; function loadJSONDoc() { xhr = null; if (window.XMLHttpRequest) {// code for Firefox, Chrome, etc. xhr = new XMLHttpRequest(); console.log(xhr.readyState); // 0 } else if (window.ActiveXObject) {// code for IE xhr = new ActiveXObject("Microsoft.XMLHTTP"); } xhr.onreadystatechange = function() { // 0,1,2,3,4 console.log(xhr.readyState) } if (xhr != null) { let data = null; const fileDOM = document.querySelector('input'); const formData = new FormData(); const files = fileDOM.files; // 元素的files属性获取文件列表 for(let file of files) { formData.append("image", file, file.name); // 第一个参数是控件名称;第三个参数是文件名 } data = formData; xhr.open("POST", '/postdata', true); // 1 xhr.send(data); } } </script> </body>
    • "application/x-www-form-urlencoded;charset=UTF-8"
    // 当POST方法的传参body内容是URLSearchParams实例时
    // Content-Type默认是"application/x-www-form-urlencoded;charset=UTF-8"
    
    /**********
      假设 URL: https://example.com?version=1.0
      则对应paramString = "version=1.0"
    */
    const searchParams = new URLSearchParams(location.search.slice(1));
    fetch('https://example.com/api', {
       method: "POST",
       body: searchParams
    })
    • "text/html;charset=UTF-8":  当传递的数据为document类型时,默认是该类型。
    data = document;
    xhr.send(data);
    • "text/plain; charset=UTF-8": 当传递的数据是对象,数字,字符串,布尔值时,默认都是该类型。

        ⚠️//单独的传"name=lyra"属于字符串,不是URLSearchParams对象。

    data = {a: 1};
    //data = "22";
    //data = 22;
    //data = true
    xhr.send(data);
    • "application/json; charset=UTF-8": 浏览器不会默认该类型,需要手动添加。

         传参数据需要JSON.stringify()处理。

    data = JSON.stringify({a: 0});
    xhr.setRequestHeader('Content-Type','application/json;charset=UTF-8');
    xhr.send(data);
    • "image/jpeg"或者"image/png": 用于FileAPI上传图片

    const xhr = new XMLRequestHeader();
    xhr.open('POST', '/', true);
    
    const fileDOM = document.querySelector('inputFile');
    const file= fileDOM.files[0];
    
    xhr.setRequestHeader('Content-Type', file.type); //可以省略,系统自动添加
    xhr.send(file);

    3.send([body])

    发送http请求。

    如果是GET方法,没有请求体body或者传null。

    POST方法需要传请求体body。

    4.getAllResponseHeaders()

    获取除了Set-Cookie和Set-Cookie2之外的所有响应头信息。

    如果无响应,返回null; 如果网络错误,返回""

    并且每个头信息单独占一行。例如:

    Cache-Control: max-age=31536000
    Content-Length: 4260
    Content-Type: image/png
    Date: Sat, 08 Sep 2012 16:53:16 GMT

    如上所示,返回的响应头信息,每一行都是以回车+换行(' ')分割,并且该规则所有操作系统都一样。

    name和value之间以冒号+空格隔开": " ,是一个固定的规范。

    所以想要获取一个name,value是对象的形式,可以如下操作:

    xhr.onreadystatechange = function() { // 只有在readyState >=3 的时候,才能获取正确的结果。
        if (xhr.readyState ===3 || xhr.readyState === 4) {
            const allHeaders = xhr.getAllResponseHeaders();
            // 注意需要清空两头的"
    ",否则会多出"":undefined
            const resultObj = allHeaders.trim().split("
    ").reduce((memo, next) => {
                let [name, value] = next.split(": ");
                if (memo[name]) { // 如果请求头重复
                    memo[name] = `${memo[name]}; ${value}`;
                } else {
                    memo[name] = value;
                }   
                return memo         
            }, {}) 
            console.log(resultObj);
        }
    }

    5.getResponseHeader(name)

    获取特定名称的响应头信息,除了Set-Cookie和Set-Cookie2

    如果有多个结果,会返回一个值,通过空格+逗号隔开。

    xhr.getResponseHeader('Content-Type');

    6.abort() 

    终止请求。xhr.abort(); 

    调用后,readyState的值变为4; status为0

    7. XHR相关事件

    除了onprogress事件,其他的均没有参数;

    所有的监听函数都应该在xhr.send()方法之前定义。

    也可以通过addEventListen('事件名', fn, false)进行监听事件的调用。

    1.onreadystatechange

    当readyState状态改变时触发;但重置时,即变为0,不触发。

    2. onloadstart

    当掉用send()方法时,触发该事件;

    3. onprogress

    监听函数有个事件对象的参数,该对象有三个属性;

    xhr.onprogress = function(event) {
      // event对象有三个参数event.loaded/event.total/event.lengthComputable
    }

    loaded: 已经传输的数据

    total: 总的数据量

    lengthComputable:  布尔值; 进度是否可以计算

    4.onload

    请求成功的监听函数;

    5. onloadend

    请求结束(成功或者失败)触发;readystate === 4

    load,error,abort事件都会随后触发loadend事件;

    6.onabort

    请求中断;调用xhr.abort()触发; 

    7.onerror

    请求失败触发;网络问题或者请求路由有误。

    8.ontimeout

    从onloadstart开始,超过设置的timeout时间触发;timeout不为0。

    8.xhr的上传对象

    xhr上有个upload属性,可以用来描述文件上传的状态。

    它有除了onreadystatechange之外,xhr有的其他7个事件。

    xhr.upload.onloadstart
    xhr.upload.onload
    xhr.upload.onerror
    xhr.upload.onloadend
    xhr.upload.onprogress
    xhr.upload.ontimeout
    xhr.upload.onabort

    通过upload的监听事件,查看当前文件上传的进度

    示例:

    <body>
      <!--
        progress标签是H5标签;闭合标签不能省略;
        value表示进度;max表示最大值;min表示最小值
      -->
      <progress value="0" min="0" max="100"></progress>
      <script>  
        const xhr = new XMLHttpRequest();
        xhr.open('POST', '/server', true);
    
        const progressBar = document.querySelector('progress');
        xhr.upload.onprogress = function(e) {
          if(e.lengthComputable) {
            const { loaded, total } = e;
            console.log(loaded, total);
            progressBar.value = (loaded/total)*100;
            // 兼容不支持 <progress> 元素的老式浏览器
            progressBar.textContent = progressBar.value;
          }
        }
        xhr.send(new Blob(['hello world']), {type: 'text/plain'});
      </script> 
    </body>
  • 相关阅读:
    Balanced Binary Tree
    Convert Sorted List to Binary Search Tree
    Convert Sorted Array to Binary Search Tree
    Binary Tree Zigzag Level Order Traversal
    Validate Binary Search Tree
    Binary Tree Level Order Traversal II
    Binary Tree Level Order Traversal
    Maximum Depth of Binary Tree
    如何把U盘的两个盘或者多个盘合成一个
    bugku 想蹭网先解开密码
  • 原文地址:https://www.cnblogs.com/lyraLee/p/11580767.html
Copyright © 2011-2022 走看看