Ajax(四)

59 阅读6分钟

Ajax第四天

一、请求报文

1.什么是请求报文和响应报文:

客户端与服务器通信的过程是基于请求与响应的。其中: ①请求报文规定了客户端以什么格式把数据发送给服务器

②响应报文规定了服务器以什么格式把数据响应给客户端

2.请求报文由请求行(request line)、请求头部( header )、空行 和 请求体 4 个部分组成。

(注意:在浏览器中,GET 请求比较特殊,它只有请求头,没有请求体。在浏览器中,POST、PUT、PATCH、DELETE 请求既有请求头,又有请求体。)

3.响应报文由状态行、响应头部、空行 和 响应体 4 个部分组成。
4.URL参数

(1)常用的5种请求方式,都可以在URL后面携带请求参数。

(2)由于URL的长度有限制,所以请求参数一般都比较小,比如不能做文件上传

(3)常用的请求参数有两种写法

/api/xxx?参数=值&参数=值    (这种格式的字符串叫做查询字符串,所以这样的参数叫做查询参数)
/api/xxx/值/值                        (Restful 风格的接口用这种格式的参数)
5.axios中 如何携带不同格式的请求参数

(1)第一种格式的参数:(/api/xxx?参数=值&参数=值)

// 直接写成查询字符串,并拼接到url后面
axios.get('/api/xxx?key=value&key=value')
// 按照axios的语法写,axios会帮我们转成查询字符串
axios.get('api/xxx', { params: { key: value, key: value } })

(2)第二种格式的参数:( /api/xxx/值/值)

// 只能自己拼接
axios.get('/api/xxx/100/zhangsan')
6.请求体

(1)除GET请求以外,其他4种常用的请求方式,都可以设置请求体。 (2)请求体的大小没有限制,所以可以提交大量的数据 (3)常用的请求体格式有如下三种:

参数=值&参数=值                    (查询字符串格式)
'{ "id": 1, "name": "zs" }'       (JSON格式)
new FormData()                    (FormData对象格式)

(4)请求的时候,设置了不同格式的请求体,需要一个对应的请求头

1651148063810.png

二、响应报文

1.http 响应状态码:

概念:http 响应状态码(Status Code)由三位数字组成,用来标识响应成功与否的状态。 作用:客户端浏览器根据响应状态码,即可判断出这次 http 请求是成功还是失败了。

2.常见的 http 响应状态码

1651148183065.png

3.http 响应状态码 Vs 业务状态码

(1)所处的位置不同:

①在响应头的状态行中所包含的状态码,或者请求列表中的Status,叫做“响应状态码”

1651148277545.png

②在响应体的数据中所包含的状态码(案例中叫做code),叫做“业务状态码”

1651148286060.png

(2)表示的结果不同:

①响应状态码只能表示这次请求的成功与否(成功地失败了)

②业务状态码用来表示这次业务处理的成功与否

(3)通用性不同: ①响应状态码是由 http 协议规定的,具有通用性。每个不同的状态码都有其标准的含义,不能乱用。

②业务状态码是后端程序员自定义的,不具有通用性。

三、原生Ajax

1.XMLHttpRequest:是浏览器内置的一个构造函数。

①作用:基于 new 出来的 XMLHttpRequest 实例对象,可以发起 Ajax 的请求。

②axios 中的 axios.get()、axios.post()、axios() 方法,都是基于 XMLHttpRequest(简称:XHR) 封装出来的!

③发起 Ajax 请求的核心对象:XMLHttpRequest

④怎样拿到服务器响应回来的数据?load 事件 和 xhr.response

2.请求时携带URL参数 或 提交请求体
// 将请求参数拼接到url后面
xhr.open('请求方式', 'http://www.itcbc.com/api/xx?id=1&username=zhangsan');
xhr.send( 请求体 );
3.提交请求体数据,需指定Content-Type头

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

// 根据请求体格式的不同,需设置对应的Content-Type头
xhr.setRequestHeader('Content-Type', '值')
5.原生Ajax

(1)创建 xhr对象

(2)调用 open方法 指定 请求类型,url

(3)发送出去 send

(4)监听onload 数据响应事件

      // 1 创建 xhr对象
      const xhr = new XMLHttpRequest();
      // 2 调用 open方法 指定 请求类型,url
      xhr.open("get", "http://www.itcbc.com:3006/api/getbooks");
      // 3 发送出去 send
      xhr.send();
      // 4 监听onload  数据响应事件
      xhr.addEventListener("load", function () {
        // this
        console.log("数据回来啦");
        // console.log(this.response);
        // 字符串转对象
        const obj = JSON.parse(this.response);
        console.log(obj);

        // 对象转字符串
        const objstr = JSON.stringify(obj);
        console.log(objstr);
      });
6.原生-get-携带参数
     const xhr = new XMLHttpRequest();
      xhr.open("get", "http://www.itcbc.com:3006/api/getbooks?appkey=123123");
      xhr.send();
      xhr.addEventListener("load", function () {
        obj = JSON.parse(this.response);
        console.log(obj);
      });
7.原生-post-携带参数
  const xhr = new XMLHttpRequest();
      // open 来指定 请求方式
      xhr.open("post", "http://www.itcbc.com:3006/api/addbook");

      const data = {
        bookname: "1从入门到精通1",
        author: "我自己",
        publisher: "黑马出版社",
        appkey: "wanshao1234",
      };

      // 把data 转成 a=b&c=d ....  URLSearchParams
      const usp = new URLSearchParams(data);
      const query = usp.toString();

      // 设置对应的 content-type
      xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
      xhr.send(query); // 传递 a=b&c=d

      xhr.addEventListener("load", function () {
        console.log(this.response);
      });
8.原生-post-携带参数-json
      const xhr = new XMLHttpRequest();
      xhr.open("post", "http://www.itcbc.com:3006/api/addbook");

      // post 三种不同数据格式的参数
      // 1 a=b&c=d   同时也需要指定 content-type 才行!!
      // 2 对象格式  {a:"b",c:"d"} 同时也需要指定 content-type 才行!!
      // 3 formdata 数据

      const data = {
        bookname: "2从入门到精通2",
        author: "我自己",
        publisher: "黑马出版社",
        appkey: "wanshao1234",
      };

      // 设置对应的 content-type
      xhr.setRequestHeader("Content-type", "application/json");
      const str = JSON.stringify(data);

      xhr.send(str); // 传递 a=b&c=d

      xhr.addEventListener("load", function () {
        console.log(this.response);
      });
9.原生-post-携带参数-formdata
<body>
    <input type="file" accept="image/*" />
    <script>
      const input = document.querySelector("input");
      input.addEventListener("change", function () {
        const file = this.files[0];
        const formdata = new FormData();
        formdata.append("avatar", file);

        const xhr = new XMLHttpRequest();
        xhr.open("post", "http://www.itcbc.com:3006/api/formdata");
        // 不用设置 content-type
        xhr.send(formdata);
        xhr.addEventListener("load", function () {
          console.log(this.response);
        });
      });
    </script>
  </body>
10.ajax代码的封装1

(1)type 可能是get 也可能是post

(2)data 3种(查询字符串 json formdata )

(3)希望封装的代码 什么样式

ajax({url,type,data,success})
        {
        url: 'http://www.itcbc.com:3006/api/getbooks',
        type: 'post',
        data: "appkey=wanshao1234",
        success(result) {
          console.log(result);
        }

(4)jq中 也是封装过 ajax代码

      // jq中 也是封装过 ajax代码
      $.ajax({
        url: "http://www.itcbc.com:3006/api/getbooks",
        type: "post",
        data: "appkey=wanshao1234",
        success(result) {
          console.log(result);
        },
      });
11.ajax代码的封装2

(1)ajax 是一个函数(正解) 还是 一个对象

(2)它接受一个 参数 格式 什么格式(对象)

(3)需要在ajax函数中 写完 整个原生ajax 发送请求的代码

const option = {
        url: "http://www.itcbc.com:3006/api/getbooks",
        type: "get",
        data: "appkey=wanshao1234",
        success(result) {
          // result 等于 要等于响应的数据 =  对象格式
          console.log(result);
        },
      };

      ajax(option);

      function ajax(config) {
        const xhr = new XMLHttpRequest();
        xhr.open(config.type, config.url + "?" + config.data);
        xhr.send();
        xhr.addEventListener("load", function () {
          //  响应的数据 this.response
          // console.log(this.response);
          const obj = JSON.parse(this.response);
          config.success(obj);
        });
      }
12.ajax代码的封装.-get-不携带参数

(1)关键代码

// 封装的时候考虑到用户 (可能带参数 , 可能不带参数)
        const xhr = new XMLHttpRequest();
        if (config.data) {
          // 有传递参数
          xhr.open(config.type, config.url + "?" + config.data);
        } else {
          xhr.open(config.type, config.url);
        }

(2)完整代码

const option = {
        url: "http://www.itcbc.com:3006/api/getbooks",
        type: "get",
        // data: 'appkey=wanshao1234',
        success(result) {
          console.log(result);
        },
      };

      ajax(option);

      ajax({
        url: "http://www.itcbc.com:3006/api/getbooks",
        type: "get",
        data: "appkey=wanshao1234",
        success(result) {
          console.log(result);
        },
      });

      function ajax(config) {
        console.log(config.data);
        // 封装的时候考虑到用户 (可能带参数 , 可能不带参数)
        const xhr = new XMLHttpRequest();
        if (config.data) {
          // 有传递参数
          xhr.open(config.type, config.url + "?" + config.data);
        } else {
          xhr.open(config.type, config.url);
        }
        xhr.send();
        xhr.addEventListener("load", function () {
          const obj = JSON.parse(this.response);
          config.success(obj);
        });
      }
13.ajax代码的封装.-get-不携带参数-优雅

(1)关键代码

// 用到解构+继承原理,有则用,无则默认data = ""
function ajax({ url, type, data = "", success }) {
        // 封装的时候考虑到用户 (可能带参数 , 可能不带参数)
        const xhr = new XMLHttpRequest();
        xhr.open(type, url + "?" + data);
        // 如果 data没有值  url =  http://www.itcbc.com?
        // 如果 data有值  url =  http://www.itcbc.com?appkey=wanshao1234
        xhr.send();
        xhr.addEventListener("load", function () {
          const obj = JSON.parse(this.response);
          success(obj);
        });
      }

(2)完整代码

      const option = {
        url: "http://www.itcbc.com:3006/api/getbooks",
        type: "get",
        // data: 'appkey=wanshao1234',
        success(result) {
          console.log(result);
        },
      };

      ajax(option);

      ajax({
        url: "http://www.itcbc.com:3006/api/getbooks",
        type: "get",
        data: "appkey=wanshao1234",
        success(result) {
          console.log(result);
        },
      });

      function ajax({ url, type, data = "", success }) {
        // 封装的时候考虑到用户 (可能带参数 , 可能不带参数)
        const xhr = new XMLHttpRequest();
        xhr.open(type, url + "?" + data);
        // 如果 data没有值  url =  http://www.itcbc.com?
        // 如果 data有值  url =  http://www.itcbc.com?appkey=wanshao1234
        xhr.send();
        xhr.addEventListener("load", function () {
          const obj = JSON.parse(this.response);
          success(obj);
        });
      }
14.ajax代码-post
      ajax({
        url: "http://www.itcbc.com:3006/api/getbooks",
        type: "get",
        success(result) {
          console.log(result);
        },
      });
      ajax({
        url: "http://www.itcbc.com:3006/api/getbooks",
        type: "post",
        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);
            data = data.toString();
          }
          xhr.open(type, url + "?" + data);
          xhr.send();
        } else if (type === "post") {
          // post请求的相关的代码
          xhr.open(type, url);
          xhr.send();
        }
        xhr.addEventListener("load", function () {
          const obj = JSON.parse(this.response);
          success(obj);
        });
      }
15.ajax代码-post-data传参

(1)判断当前data的数据类型

①字符串类型

xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send(data); // 传递 a=b&c=d

②对象类型

xhr.setRequestHeader("Content-type","application/json");
const str =JSON.stringify(data);
xhr.send(str); // 传递 a=b&c=d

③formdata

xhr.send(formdata);

(2)完整代码

①判读类型:get/post

②判断data数据类型

③执行对应的请求代码

      const input = document.querySelector("input");
      input.addEventListener("change", function () {
        const file = this.files[0];
        const formdata = new FormData();
        formdata.append("avatar", file);

        ajax({
          url: "http://www.itcbc.com:3006/api/formdata",
          type: "post",
          data: formdata,
          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);
        });
      }

四、防抖和节流

1.防抖(debounce)指的是:频繁触发某个操作时,只执行最后一次
2.防抖应用场景:

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

(3)原理:

1)用在输入框中 实现 不用用户按下回车键 就发送请求

2)技术原理

①应用新的一次输入来清除上一次的延时器

②同时开启一个新的延时器

3.防抖核心代码
 clearTimeout(timeid);
        // 开启了一个延时器 里面代码 1s后会执行
        timeid = setTimeout(function () {
          const value = input.value.trim();
          const queryStr = `?bookname=${value}`;
          getData(queryStr);
        }, 1000);
4.防抖完整代码
      getData();
      // change事件  输入框的值发生改变-输入框失去焦点 才触发
      // input 事件

      // 定义一个 演示器 id
      let timeid; // 钻 石 城 堡

      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);
      });

      function getData(query = "") {
        axios({
          method: "get",
          url: "http://www.itcbc.com:3006/api/getbooks" + query,
          // params:{},
        }).then((result) => {
          console.log(result);
          const arr = result.data.data;
          render(arr);
        });
      }

      function render(arr) {
        let html = arr
          .map(
            (value) => `
      <tr>
          <td>${value.id}</td>
          <td>${value.bookname}</td>
          <td>${value.author}</td>
          <td>${value.publisher}</td>
        </tr>
      `
          )
          .join("");
        document.querySelector("tbody").innerHTML = html;
      }
5.节流(throttle)指的是:单位时间内,频繁触发同一个操作,只会触发 1 次。
6.节流应用场景:

射击游戏中,单位时间内只能发射一颗子弹;上一次的业务没有结束的话 不允许开启下一次业务使用场景 移动端分页 - 倒计时按钮 等等


      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;
        });
      }