第三天的啊贾克斯 上号!

420 阅读7分钟

Ajax XMLHttpRequest & 跨域:

一.XMLHttpRequest:

XMLHttpRequest是浏览器内置的一个构造函数

作用:基于 new 出来的 XMLHttpRequest 实例对象,可以发起 Ajax 的请求。 axios 中的 axios.get()、axios.post()axios() 方法,都是基于 XMLHttpRequest(简称:XHR) 封装出来的!

使用 XMLHttpRequest 发起 GET 请求:

主要的 4 个实现步骤:

  • 创建 xhr 对象

  • 调用 xhr.open() 函数

  • 调用 xhr.send() 函数

  • 监听 load 事件

        <script>
            let xhr = new XMLHttpRequest();
            xhr.open('GET', 'http://xxx.com/api/xx');
            xhr.send();
            xhr.addEventListener('load', function () {
                console.log(this.response);
            })
        </script>
    

请求时携带URL参数 或 提交请求体 :

  • URL参数,只能拼接URL 地址 后面
  • 请求体,放到 send() 里面
    <script>
        let xhr = new XMLHttpRequest();
        // 将请求参数拼接到url后面
        xhr.open('请求方式', 'http://www.itcbc.com/api/xx?id=1&username=zhangsan');
        xhr.send(请求体);

        xhr.addEventListener('load', function () {
            console.log(this.response);
        })
    </script>

提交请求体数据,需指定Content-Type头:

当需要提交请求体数据时,需要在 xhr.open() 之后,调用 xhr.setRequestHeader() 函数,指定请求体的编码格式

    <script>
        let xhr = new XMLHttpRequest();

        // 将请求参数拼接到url后面
        xhr.open('POST', 'http://www.itcbc.com/api/post');
        // 根据请求体格式的不同,需设置对应的Content-Type头
        xhr.setRequestHeader('Content-Type', '值')
        xhr.send('username=zs&age=20');

        xhr.addEventListener('load', function () {
            console.log(this.response);
        })
    </script>

请求体格式 和 对应的Content-Type值:

为了方便服务器接收数据,当提交请求体时,需要指定一个叫做Content-Type的请求头

请求体格式Content-Type是否需要在代码中指定
参数=值&参数=值application/x-www-form-urlencoded
'{ "id": 1, "name": "zs" }'application/json
new FormData()multipart/form-data; xxxxxxxxx随机字符否,浏览器自动设置

例:xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')

使用axios就不用关心这个请求头了,因为axios已经帮我们处理好了加请求头这件事,不过写原生代码,就需要自己指定

二.数据交换格式:

数据交换格式,就是服务器端客户端之间数据传输的格式

两种数据交换格式:

  • XML(很少用)
  • JSON(主流)

什么是 JSON:

  • JSON(全称:JavaScript Object Notation)是一种数据交换格式,它本质上是用字符串的方式来表示对象数组类型的数据

  • JSON 数据的格式有两种:对象格式 数组格式

  • JSON 的语法要求

    • 属性名必须使用双引号包裹

    • 字符串类型的值必须使用双引号包裹

    • JSON 中不允许使用单引号表示字符串

    • JSON 中不能写注释

    • JSON 的最外层必须是对象数组格式(其他类型也可以,但多数是对象或数组格式)

    • 不能使用 undefined函数作为 JSON 的值

  • 对象格式的 JSON 数据,最外层使用 { } 进行包裹,内部的数据为 "key": "value" 的键值对结构:

    • key 必须使用英文的双引号进行包裹
    • value 的值只能是字符串、数字、布尔值、null、数组、对象类型(可选类型只有这 6 种)
  • 数组格式的 JSON 数据

    • 最外层使用 [ ] 进行包裹,内部的每一项数据之间使用英文的 , 分隔。其中: 每一项的值类型只能是字符串、数字、布尔值、null、数组、对象这 6 种类型之一。
  • 调用浏览器内置的 JSON.parse() 函数,可以把 JSON 格式的字符串转换为 JS 数据

  • 调用浏览器内置的 JSON.stringify() 函数,可以把 JS 数据转换为 JSON 格式的字符串

序列化和反序列化:

  • 真实数据转换为字符串的过程,叫做序列化 调用 JSON**.stringify()** 函数进行 JSON 的序列化

  • 字符串转换为真实数据的过程,叫做**反序列化 ** 调用 JSON.parse() 函数进行 JSON 的反序列化

把 XMLHttpRequest 请求到的 JSON 数据反序列化为 JS 对象:

在 xhr 对象的 load 事件中,通过 xhr.response 访问到的是 JSON 格式的字符串数据。可以调用 JSON.parse() 函数将 xhr.response 转化为 JS 对象

    <script>
        let xhr = new XMLHttpRequest();
        // 将请求参数拼接到url后面
        xhr.open('请求方式', 'http://www.itcbc.com/api/xx?id=1&username=zhangsan');
        xhr.send(请求体);
        xhr.addEventListener('load', function () {
            let res = JSON.parse(this.response);//需要将xhr.response 转化为 JS 对象
            console.log(res);
        })
    </script>

补充 - JSON 文件:

后缀名是 .json 的文件叫做 JSON 文件,专门用来存储 JSON 格式的数据。

注意:.json 结尾的文件,一般都是项目的配置文件

三.封装自己的 Ajax 函数:

定义ajax函数的参数选项:

自定义的 Ajax 函数,它接收一个配置对象作为参数。配置对象中包含如下 5 个参数选项:

参数选项说明
method请求的类型(GET 或 POST)
url请求的 URL 地址
data请求体数据,有三种格式,分别是(FormData 格式、JSON 格式、普通字符串格式)
success请求成功之后的回调函数

实现步骤:

  1. 创建 xhr 实例对象
  2. 根据用户指定的 method 和 url 发起对应的请求
  3. 把响应的 JSON 数据转换为 JS 对象
  4. 调用 success 成功的回调,把请求的结果当作参数传递进去

注意事项:

  1. 有get post 请求分开类型
  2. data数据有三种类型 string object formdata 区分开
  3. post请求 xhr.setRequestHeader设置对应的请求头的 Content-Type 类型
  4. data=FormDatainstanceof 的运用 实例 instanceof 构造函数

请求通用代码如下:

    <input type="file" accept="image/*">
    <script>
        axios({
            type: 'get',
            url: 'http://www.itcbc.com:3006/api/getbooks',
            data: {
                publisher: '黑马出版社',
                appkey: 'lijiahao123'
            },
            success(result) {
                console.log(result);
            }
        })
        function ajax({ url, type, data = '', success }) {
            const xhr = new XMLHttpRequest();
            // 判断 请求类型
            if (type === 'get') {
                // get请求的相关的代码
                if (typeof data === 'object') {
                    data = new URLSearchParams(data).toString();
                }
                xhr.open(type, url + '?' + data);
                xhr.send();
            } else if (type === 'post') {
                // post请求的相关的代码
                xhr.open(type, url);

                // 判断是不是字符串
                if (typeof data === 'string') {
                    xhr.setRequestHeader(
                        'Content-type',
                        'application/x-www-form-urlencoded'
                    );
                    xhr.send(data);
                } else if (typeof data === 'object') {
                    // 判断是不是对象

                    // 判断是不是 FormData 实例
                    if (data instanceof FormData) {
                        // 是 FormData 实例
                        xhr.send(data);
                    } else {
                        // 普通的对象
                        xhr.setRequestHeader('Content-type', 'application/json');
                        const str = JSON.stringify(data);
                        xhr.send(str); // 传递 a=b&c=d
                    }
                }
            }
            xhr.addEventListener('load', function () {
                const obj = JSON.parse(this.response);
                success(obj);
            });
        }
    </script>

四.同源策略 & 跨域:

同源:

同源指的是两个 URL 地址具有相同的协议、主机名、端口号

例如,下表给出了相对于 www.test.com/index.html 页面的 5 个同源检测结果:

URL是否同源原因说明
www.test.com/other.html同源(协议、域名、端口相同)
www.test.com/about.html协议不同(http 与 https)
blog.test.com/movie.html域名不同(www.test.com 与 blog.test.com)
www.test.com:7001/home.html端口不同(默认的 80 端口与 7001 端口)
www.test.com:80/main.html同源(协议、域名、端口相同)

同源策略:

同源策略(英文全称 Same origin policy)是浏览器提供的一个安全功能浏览器同源策略规定:不允许非同源的 URL 之间进行资源的交互

例:

跨域:

同源指的是两个 URL 的协议、主机名、端口号完全一致,反之,则是跨域

出现跨域的根本原因:浏览器的同源策略不允许非同源的 URL 之间进行资源的交互。

浏览器允许发起跨域请求。但跨域请求回来的数据,会被浏览器拦截,无法被页面获取到

突破浏览器跨域限制的两种方案:

JSONPCORS实现跨域数据请求的两种技术方案

方案诞生的时间方案来源优点缺点
JSONP出现较早民间(非官方)兼容性好(兼容低版本 IE)仅支持 GET 请求
CORS出现较晚W3C 官方标准支持 GET、POST、PUT、DELETE、PATCH等常见的请求方式不兼容某些低版本浏览器

注意:目前 JSONP 在实际开发中很少会用到CORS 是跨域的主流技术解决方案

CORS 的两个主要优势:

  • CORS 是真正的 Ajax 请求,支持 GET、POST、DELETE、PUT、PATCH 等这些常见的 Ajax 请求方式
  • 只需要后端开启 CORS 功能即可,前端的代码无须做任何改动

JSONP:

JSONP实现跨域数据请求的一种技术解决方案。它只支持 GET 请求,不支持 POST、DELETE 等其它请求

  • 在实际开发中很少被使用
  • 在面试中可能会问到 JSONP 的原理

在解决跨域问题时:

  • CORS 方案用到了 XMLHttpRequest 对象,发起的是纯正的 Ajax 请求
  • JSONP 方案没有用到 XMLHttpRequest 对象,因此,JSONP 不是真正的 Ajax 技术

结论:只要用到了 XMLHttpRequest 对象,发起的就是 Ajax 请求!

JSONP 的底层实现原理:

JSONP 在底层,用到了

原因:

JSONP 的底层实现原理:

  • 非同源的 JavaScript 代码请求到本地,并执行:

    <body> 
      <!-- 把非同源的 JavaScript 代码请求到本地,并执行 -->
      <script src="http: //www.itcbc.com:3006/api/getscript"></script>
    </body>
    
    
  • 如果请求回来的 JavaScript 代码只包含函数的调用,则需要程序员手动定义 show 方法。

    <body>
      <script>
        // 1. 手动定义 show 方法
        function show(data) {
          console.log(data)
        }
      </script>
        
      <!-- 2. 把非同源的 JavaScript 代码请求到本地,并执行 --> 
      <script src="http: //www.itcbc.com:3006/api/getscript2"></script>
    </body>
    

    缺点:服务器响应回来的代码中,调用的函数名是写死的

  • 在指定 时,可以通过查询参数中的 callback,自定义回调函数的名称:

    <script>
      // 1. 手动定义 showInfo 方法
      function showInfo(data) {
        console.log(data)
      }
    </script>
    <!-- 通过 callback 参数,自定义回调函数的名字 -->
    <script src="http: //www.itcbc.com:3006/api/jsonp?callback=showInfo"></script
    
  • 在指定 时,还可以通过查询参数的方式,指定要发送给服务器的数据:

    <script>
      // 1. 手动定义 showInfo 方法
      function showInfo(data) { console.log(data) }
    </script>
    <!-- 通过 callback 参数,自定义回调函数的名字 -->
    <!-- 指定 name 和 age 这两个参数 -->
    <script src="http: //www.itcbc.com:3006/api/jsonp?callback=showInfo&name=zs&age=20"></script>
    

五.防抖 & 节流:

防抖:

防抖(debounce)指的是:频繁触发某个操作时,只执行最后一次

防抖的应用场景:

场景:搜索框只在输入完后,才执行查询的请求。 好处:这样可以有效减少请求的次数,节省网络资源。

核心代码:

    <script>
        /* 防抖  防止抖动
         1 用在输入框中 实现 不用用户按下回车键 就发送请求
         2 技术原理
         1 用新的一次输入来清除上一次的延时器
         2 同时开启一个新的延时器 */
        const input = document.querySelector('input');
        input.addEventListener('input', function (event) {
            clearTimeout(timeid);
            // 开启了一个延时器 里面代码 1s后会执行
            timeid = setTimeout(function () {
                const value = input.value.trim();
                const queryStr = `?bookname=${value}`;
                getData(queryStr);
            }, 1000);
        });
    </script>

节流:

节流(throttle)指的是:单位时间内,频繁触发同一个操作,只会触发 1 次

节流的应用场景:

射击游戏中,单位时间内只能发射一颗子弹。

核心代码:

    <script>
        // 这一次请求还没有结束 就不能开启下一个请求
        // 业务 分页 业务
        // 开关
        let isLoadding = false; // 有没有请求在发送当中

        // 点击按钮的时候先判断 isLoadding true还是false
        //  true 请求在发送中  return
        //  false 没有请求
        //   先设置 isLoadding true
        //   发送请求出去
        //  请求回来了  设置 isLoadding = false

        document.querySelector('button').addEventListener('click', function () {
            if (isLoadding) {
                return;
            }
            isLoadding = true;
            // 发送请求的时候  禁用按钮
            // this.disabled=true;
            getData();
        });
        function getData(query = '') {
            console.log('请求发送出去');
            axios({
                method: 'get',
                url: 'http://www.itcbc.com:3006/api/getbooks' + query,
                // params:{},
            }).then((result) => {
                console.log('数据回来了');
                // document.querySelector('button').disabled=false
                isLoadding = false;
            });
        }
    </script>