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>
  • 相关阅读:
    推荐体系算法总结
    Springboot 多模块调用,找不到注入的类
    LRU算法
    在SQLServer中连接另一个SQLServer库数据,在Oracle中连接另一个Oracle库数据,在SQL Server中连接Oracle数据,在Oracle中连接SQL Server数据
    用C#实现木马程序
    CSS filter 滤镜可视化配置
    微信小程序农历日期选择器 lunarpicker
    ms Sql 数据库出现 “提供的统计信息流已损坏”的解决办法。
    自制《要塞:十字军东征》无限金钱修改器
    c#+Winform实现自定义的“复制、粘贴”右键快捷菜单,多个控件共享使用一个右键菜单。
  • 原文地址:https://www.cnblogs.com/lyraLee/p/11580767.html
Copyright © 2011-2022 走看看