关于AJAX的使用方法

83 阅读9分钟

Ajax

服务器相关的基础概念

服务器

服务器的本质:也是一台电脑。

服务器的作用:

存储一个网站的文件(HTML、CSS、JS、图片、音乐.....)

提供网站的文件给用户

如何获得服务器

购买(京东、淘宝……)

租赁(阿里云、腾讯云……)

资源

服务器上的 网页(html文件)、图片、音乐、视频、字体文件、CSS文件、JS文件等等都称之为资源。所以资源代指服务器上存储的内容。

通俗的讲,我们浏览网页时,从网络当中看到的内容都叫做资源。

数据也是资源

网页中的数据,也是服务器对外提供的一种资源。例如股票数据、各行业排行榜等。

数据

服务器多数情况都使用数据表的方式来存储数据,和我们平时见到的表格差不多,形式如下:

1650810708838.png

客户端

概念:在前端开发中,客户端特指“Web 浏览器”。

作用:将互联网世界中的 Web 资源加载、并呈现到浏览器窗口中供用户使用。

最常见的“客户端浏览器”都有哪些:

1650810764473.png

URL 地址(统一资源定位符)

服务器上的每个资源,都对应着独一无二的URL地址

1650810870486.png

数据也是服务器上的资源

对数据的操作增删改查,也对应着不同的URL地址

1650810910908.png

示例

<script>
      /* 
      想要获取服务器上的数据 url ,它是后端程序员提供  
      http://www.itcbc.com:3006/api/getbooks  图书数据 

      我们需要通过代码的方式  把服务器上的数据 变成 一个普通的变量 数组
      给我数组了 我就懂得如何去页面渲染了  第三方的一个js的帮助 

      axios
      1 下载 引入到项目中
      2 根据url的地址 来编写代码 
        1 获取数据 -get   ( 请求类型  1  get 2 post 3 delete  4 put 5 patch  )
        2 编写代码
       */

      //  开始向服务器 发送请求 索要数据
      axios({
        //  method:"请求类型",
        //  url:"资源地址",
        method: 'get',
        url: 'http://www.itcbc.com:3006/api/getbooks',
      }).then((result) => {
        //  如果这个代码可以触发 数据回来了
        // console.log(result); // 服务器给我们返回的数据!!
        // 数组数据

        // 给你了一个数组 arr 数组的格式
        const arr = result.data.data; // 字段的名称 id、bookname、author。publisher 固定
        // console.log(arr);
        // 你 有能力 根据 数组 来 显示到页面中

        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;
      }
    </script>

客户端与服务器通信的过程

就像我们(客户)去银行(服务场所)办理业务:

客户提出需求:客户提出要办理业务,比如办卡、存钱、取钱、销户、买纪念币等等

银行的回应:银行根据客户的需求,办理相关的业务

客户端与服务器之间的通信过程,分为请求 - 响应两个步骤。其中:

请求的概念:客户端通过网络去找服务器要资源的过程,叫做“请求

响应的概念:服务器把资源通过网络发送给客户端的过程,叫做“响应

1650811038552.png

什么是 Ajax

Ajax 是浏览器中的技术:用来实现客户端网页请求服务器的数据

它的英文全称是 Asynchronous Javascript And XML,简称 Ajax。

1650811105014.png

网页中 Ajax 的应用场景无处不在,有数据的地方就有 Ajax!

请求方式

使用 Ajax 请求数据的 5 种方式

Ajax中,客户端浏览器在请求服务器上的数据时,根据**操作性质(增删改查)**的不同,可以分为以下 5 种常见的操作:

1650811278660.png

GET 请求

GET 请求用于从服务器获取数据:

1650811490045.png

POST 请求

POST 请求用于向服务器新增数据:

1650811600487.png

DELETE 请求

DELETE 请求用于删除服务器上的数据:

1650811630108.png

PUT 请求

PUT 请求用于更新服务器上的数据(侧重于完整更新:例如更新用户的完整信息):

1650811679011.png

PATCH 请求

PATCH 请求用于更新服务器上的数据(侧重于部分更新:例如只更新用户的手机号):

1650811711335.png

请求方式小结

操作服务器上的数据除了要使用 URL地址,还需要指定______请求方式_______

操作服务器上的数据时:

获取服务器上的数据,需要使用 GET 方式

新增(添加)数据,需要使用 ____POST 方式

删除数据,需要使用 ____DELETE 方式

完整修改(更新)数据,需要使用 ____PUT 方式

修改(更新)部分数据,需要使用 ____PATCH 方式

Ajax 的基础用法

axios(发音:艾克C奥斯) 是前端圈最火的、专注于数据请求的库。

Axios

1650812383649.png

中文官网地址:www.axios-http.cn/

英文官网地址:www.npmjs.com/package/axi…

Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。

特性

  • 从浏览器创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求和响应数据
  • 取消请求
  • 自动转换JSON数据
  • 客户端支持防御XSRF

axios 的基本语法如下:

1650812427162.png

GET 请求

测试 GET 请求的 URL 地址为 www.itcbc.com:3006/api/getbook…

1650812457372.png

示例

    <!-- 1 引入axios -->
    <script src="./lib/axios.js"></script>
    <script>


/* 
1 资源的地址 问后端要即可 
2 我们负责用对 代码 确保 数据可以请求成功 
3 不需要纠结 result的数据格式 
      只需要打印出result ,在里面 resut.data 找到数据  
      自己截图数据
4 把数据 存在自己的一个数组中
5 使用以前教过知识把数组渲染到页面中 

 */
      axios({
        method: 'get',
        url: 'http://www.itcbc.com:3006/api/getbooks',
      }).then((result) => {
        console.log(result);
        // result 请求成功的结果
        // then 固定!! 是axios封装的一个代码  意思 服务器把数据返回了,then里面的代码就会被触发
        // 底层套了两层data 也是后台程序员做的,不用纠结 别人怎么定义的 我只负责如何拿对
        const arr = result.data.data; // 字段的名称 id、bookname、author。publisher 固定
        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;
      }
    </script>

GET 请求的查询参数

刚才查询回来的是所有图书的列表数据,如果想指定查询的条件,可以通过 params 选项来指定查询的参数:

如果要携带多个参数,只需要在 params 对象中指定多个查询参数项即可。示例代码如下:

1650888811057.png

1650888850241.png

指定参数查询演示

    <!-- 1 引入axios -->
    <script src="./lib/axios.js"></script>
    <script>
      /* 
    小结
    1 在实际开发过程种,我们可以在前端 指定参数来查询对应的数据 
    2 指定参数的 参数的代码写法 必须要写在
      params 对象中,以 键值对的形式存在
    3 params 对象中,写什么样的键值对 规定要由后端来决定  前端不懂的时候问他

       */
      axios({
        // 请求方式
        method: 'get',
        // 请求地址
        url: 'http://www.itcbc.com:3006/api/getbooks',
        // 请求的参数
        params: {
          // 固定
          // 键值对 是需要问后端程序员才知道
          // bookname:"万少"// 后端就会返回 书名 为 万少的一堆数据
          // author:"王勇"// 如果你这么写 后端什么都不返回(规则后端制定 )

          // 在真实的开发场景中 往往会出现 前端以为我的代码参数都写对了 为什么没有结果
          // 后端程序员都没有写到那个功能 !

          // id:5913  // 根据id来查询数据  后端已经做好这个功能了

          // bookname: '万少',
          // author: '小马',
          publisher: '6666',// 后端没有做这个功能
        },
      }).then((result) => {
        console.log(result);
        const arr = result.data.data; // 字段的名称 id、bookname、author。publisher 固定
        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;
      }
    </script>

另一种查询方式

<script src="./lib/axios.js"></script>
    <script>
      axios({
        method: 'get',
        // url: 'http://www.itcbc.com:3006/api/getbooks',
        // params: { // 推荐直观 
        //   id: 5913,
        //   bookname: 小黑,
        // },
        // url: 'http://www.itcbc.com:3006/api/getbooks?id=5913',
        // url: 'http://www.itcbc.com:3006/api/getbooks?bookname=万少',
        url: 'http://www.itcbc.com:3006/api/getbooks?bookname=小黑&id=5913',// ?属性名=属性值&属性名=属性值
      }).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;
      }
    </script>

GET 案例:图书列表查询(用回车键)

<script>
        // 1 打开页面  发送一个ajax 请求 获取数据 -  渲染页面
        books()
        // 2 获取输入框
        const input = document.querySelector('input')
        input.addEventListener('keydown', function (e) {
            // 2.1 判断 按下的是不是回车键
            if (e.key === 'Enter') {
                const value = this.value.trim(); // trim() 去除 输入框的值 的两侧的 空字符串
                // 2.3 判断是不是空字符串
                if (value) {
                    // url 传参 ?属性名 = 属性值
                    const queryStr = `?bookname=${value}`;
                    books(queryStr); // 把参数带过去
                }
                // 空字符串
                else {
                    books()
                }
            }
        })
        // 封装使用ajax来获取数据的函数
        function books(query = '') {
            axios({
                method: 'get',
                url: 'http://www.itcbc.com:3006/api/getbooks' + query,

            }).then((result) => {
                console.log(result);
                const arr = result.data.data; // 字段的名称 id、bookname、author。publisher 固定
                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;
        }
    </script>

POST 请求

使用 axios 发起 POST 请求时,只需要将 method 属性的值设置为 'POST' ,URL地址改为 '/api/addbook':

1650889527348.png

POST 案例:添加图书

思路:

点击 “添加” 按钮 获取输入框的值

使用 axios 发送Ajax请求,提交数据

如果添加成功,重新渲染页面中的数据

<button>添加</button>
    <script src="../../JS/axios.js"></script>
    <script>
        const button = document.querySelector('button')
        button.addEventListener('click', function(){
            axios({
                method: 'post',
                url: 'http://www.itcbc.com:3006/api/addbook',
                data: {
                    bookname:'人生长恨水长东',
                    author:'晚年不详',
                    publisher:'治愈书籍 强烈推荐'
                }
            }).then((result) => {
                console.log(result);
            });
        })
    </script>

delete请求

删除图书

示例

参照接口文档,发现删除图书,需要使用必填的id参数。

循环遍历数据时,将id值存储到 删除按钮的 自定义属性(data-id)中

单击 删除 按钮时,获取自定义属性data-id的值,这个值就是id

参照接口文档,配合axios的语法,发送请求,完成删除。

删除成功后,调用 books1(前面封装的获取图书函数),更新页面数据

confirm js中自带 确认框

如果用户点击 确定 返回true 点击 取消 - false

     // 删除
        const tbody = document.querySelector('tbody')
        tbody.addEventListener('click',function(e){
            if(e.target.className === 'del'){
                // 删除确认框
                // confirm  js中自带 确认框
                if(!confirm('是否确认删除')){
                    // 叹号取反 不删除则停止继续操作
                    return
                }
                const {id} = e.target.dataset
                axios({
                method: 'delete',
                url: 'http://www.itcbc.com:3006/api/delbook',
                params:{id}

            }).then((result) => {
                console.log(result);
                books1()
            });
            }
        })

appkey身份认证

服务器存储的图书,分为通用数据个人数据

默认获取、添加、删除、修改的都是通用数据。

在获取、添加、删除、修改时,如果带appkey参数,则表示使用个人数据。

1650939732341.png

1650939900937.png

修改图书

修改,最起码,得有修改的输入框。下面给出几种方案:

点击编辑,出现弹框

点击编辑,下拉一行,进行编辑

没有 编辑 按钮,点击单元格,创建input,进行修改

	const tbody = document.querySelector('tbody');
        // 全局变量
        let arr;
        // 书名
        const booknameValue = document.querySelector('.bookname');
        // 作者
        const authorValue = document.querySelector('.author');
        // 出版社
        const publisherValue = document.querySelector('.publisher');
        // 点击事件
        tbody.addEventListener('click', function (event) {
            // 判断找到的是不是这个类名
          if (event.target.className === 'editbtn') {
            // 获取a身上的下标
            const { index } = event.target.dataset;
            //  获取到 另外一个方法中的 数组
            console.log(arr[index]);
            // 把对应的数据显示到表单中
            booknameValue.value=arr[index].bookname;
            authorValue.value=arr[index].author;
            publisherValue.value=arr[index].publisher;
          }
        });
	btnadd.addEventListener('click', function () {
            // 获取表单的值
            const data = {
                // 如何去获取
                id: id,
                bookname: booknameValue.value,
                author: authorValue.value,
                publisher: publisherValue.value,
                appkey: 'lin123'
            };
            // 发送一个编辑 请求
            axios({
                url: 'http://www.itcbc.com:3006/api/updatebook',
                method: 'put',
                // query - params
                // body  - data
                data,
            }).then((result) => {
                console.log(result);
                getData();
            });
            // 提示编辑成功 ->调用 getData 实现重新获取最新的数据
        });

如何获取指定form表单内的选择器

<style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
      input[name] {
        /* <input type="text" name="username" /> */
        /* 表示选择到了 有name属性的input标签 */
        background-color: red;
      }
    </style>
  </head>
  <body>
    <form class="f1">
      <input value="111" type="text" name="username" />
      <input value="222" type="text" name="password" />
      <input value="333" type="text" name="address" />
      <input value="444" type="text" name="phone" />
      <input type="text" />
      <input type="text" />
      <input type="text" />
      <button type="button">注册数据</button>
    </form>

    <form class="f2" action="">
      <input type="text" name="nickname" value="aabbcc" />
    </form>
    <script>
      // 获取表单1 数据 对象格式
      const obj1 = getForm('.f1');
      // 获取表单2 数据 对象格式
      const obj2 = getForm('.f2');

      console.log(obj1);
      console.log(obj2);

      // query 只能传入 form标签的选择器
      function getForm(query) { // 在定义函数的时候写形参 - 名字都可以随意改 
        const inputs = document.querySelectorAll(query + ' input[name]');
        // const inputs = document.querySelectorAll('.f1 input[name]');
        const obj = {};
        inputs.forEach((dom) => {
          obj[dom.name] = dom.value;
        });

        return obj;
      }
    </script>

服务器数据的变化

当添加图书后,页面的数据没有变化,怎么办?

我们必须弄清楚数据是怎么变化的。

1650889674048.png

接口相关的基础概念

1、接口的概念

使用 Ajax 请求数据时,被请求的 URL 地址,就叫做数据接口(简称:接口或 API 接口)。

同时,每个接口必须有对应的请求方式。例如:

www.itcbc.com:3006/api/getbook… 获取图书列表的接口(GET 请求) www.itcbc.com:3006/api/addbook 添加图书的接口(POST 请求)

2、接口文档的概念

接口文档就是接口的使用说明书,它是我们调用接口的依据。

接口文档的格式

组成部分说明
接口名称接口的名称,用来快速区分每个接口的作用。如:登录接口、添加图书接口
接口 URL客户端发起 Ajax 调用此接口时,请求的 URL 地址
请求方式接口的请求方式,如:GET、POST、PUT、DELETE 等
请求参数请求此接口时,需要发送到服务器的查询参数或请求体
返回示例当接口请求成功后,服务器响应回来的数据的基本格式
返回参数说明接口响应结果的详细描述

1650890272396.png

network面板

开发或学习时,难免会遇到错误。遇到ajax方面的错误,该怎么排查呢?

答案是浏览器的 network 面板。

network,翻译为 “网络”

浏览器的开发者工具中,有一个面板为 network。(新版的chrome浏览器是中文版本的)

该工具可以抓取到所有的网络请求,当然包括ajax请求

我们可以使用该工具,查看当前Ajax请求的详细信息

​ 查看请求方式

​ 查看请求的URL地址

​ 查看请求参数

​ 查看响应结果

注意事项

有关Ajax方面的错误,不应只查看 “Console”面板,必须通过 “Network”面板进行排查

network面板介绍

1650890821755.png

network面板常用的设置

隐藏时间轴。初学阶段,用不到时间轴,可以将其隐藏,从而节省面板的空间

1650890899505.png

禁用浏览器缓存

1650890925900.png

模拟网络(网速)

No throttling -- 不限速

Fast 3G -- 模拟快速3G网络

Slow 3G – 模拟慢速3G网络

1650890950762.png

显示请求方式

1650890976232.png

network面板 查看 请求状态

非常重要

1650891025304.png

200 表示成功

pending 表示等待(可能网络不好或者断网了)

4xx 和 5xx 都表示不同程度的错误

Failed 表示失败

查看请求方式和完整URL

1650891069693.png

查看 传输到服务器的数据

1650891099222.png

查看 服务器响应结果

1650891125879.png

form 表单

了解

在网页中,表单主要负责数据采集功能

表单的三个组成部分

网页中采集数据的表单由三个部分组成,分别是:表单标签、表单域、表单按钮

1、表单标签 ------- HTML 的 < f or m > 就是表单标签,它是一个“容器”,用来将页面上指定的区域划定为表单区域

2、表单域 ------- 表单域提供了采集用户信息的渠道

常见的表单域有:input、textarea、select 等。

3、表单按钮 ------- 当表单数据填写完毕后,用户点击表单按钮,会触发表单的提交操作,从而把采集到的数据提交给服务器

数据提交给服务器时,需要指定请求的方式与请求的 URL 地址

form 标签的属性一览表

form 标签最重要的 3 个属性分别是 action、method 和 enctype。简介信息如下表所示

1650973038893.png

注意:enctype 属性只能搭配 POST 提交方式一起使用;如果是 GET 提交,则 enctype 没有意义!

以 GET 方式提交表单数据

在 form 标签上,通过 action 属性指定提交的 URL 地址,通过 method 属性指定提交的方式为 GET

以 POST 方式提交表单数据

在 form 标签上,通过 action 属性指定提交的 URL 地址,通过 method 属性指定提交的方式为 POST,并通过 enctype 属性指定数据的编码方式为 application/x-www-form-urlencoded

表单提交的问题

产生问题的原因:

表单身兼数职:既负责采集数据,又负责把数据提交到服务器!表单的默认提交行为会导致页面的跳转。

解决方案: form 表单只负责采集数据; Ajax 负责将数据提交到服务器。(符合:职能单一的原则)

旧方式

    <!-- 
      旧方式 提交数据 form标签的方式 提交
      1 肯定会出现 刷新页面 调整页面的情况 (体验! 很糟糕)
      2 输入框没name属性 没有把数据 提交给到后端
​
      新的方式 ajax 
      1 异步 网络请求 (异步 同时执行多个事情 - 你一边正在使用网页功能而且数据提交 同时进行(整个网页 ))
      2 规范  只要写到input标签想要数据提交 习惯的加上 name属性
        如果使用ajax的技术来提交数据  是完全不给标签添加name属性 
      3 习惯下来  form input标签name 都一直在使用   
      
     -->
    <form action="http://www.itcbc.com:3006/api/getbooks" method="get">
      <div>
        <label for="">用户名</label>
        <input type="text" name="username">
      </div>
      <div>
        <label for="">密码</label>
        <input type="text" name="password">
      </div>
      <div>
        <label for="">随便的测试</label>
        <input type="text">
      </div>
      <!-- <button type="submit">提交</button> -->
      <button >提交</button>
    </form>

新的方式

<form>
        <input type="text" name="username" />
        <input type="text" name="password" />
        <input type="text" name="gender" />
        <button type="button">获取表单数据</button>
    </form>
    <script>
        const button = document.querySelector('button')
​
        button.addEventListener('click', function () {
            const data1 = getForm('form')
            console.log(data1);
            return
            // 把 form表单-里面所有的表单标签-name属性 转成 formdta对象
            // const formObj = new FormData(document.querySelector('form')); 
            // formObj  对象 包含所有的表单数据(input name)
            // console.log(formObj); // 直接打印 看不见里面的数据!!
            // formObj 有forEach 方法 会遍历 它当中包含着 表单的数据
            // formObj.forEach((值,键)=>{});
        })
​
        function getForm(query) {
            //  FormData  js内置的对象  处理表单数据  需要被new 出来使用
            // 1 快速 把 form表单中的带有name属性的数据 设置到 formdata 中
            // const form = new FormData(document.querySelector('form'));
            const form = new FormData(document.querySelector(query))
            // 2 创建把数据 转成 get 参数格式 对象
            // URL Search Params 用来处理 url上的参数 对象 也是可以被new
            const usp = new URLSearchParams()
            // 3 对form遍历
            form.forEach((value, key) => {
                usp.append(key, value)
            })
            // 4 usp 获取到了所有它等待转化的数据  开始进行转化
            // 把添加到它身上的 数据 转成 url 的参数的格式
            const data = usp.toString()
            return data
        }
        /*
     FormData  快速获取表单的数据
     1 forEach
     URLSearchParams 数据转成 get传参数据格式 
     1 append
     2 toString()
      */
    </script>

jQuery 的 serialize() 函数

jQuery 的 serialize() 函数能够一次性获取到表单中采集的数据,它的语法格式如下: $('表单元素的选择器').serialize();

serialize() 函数的使用注意点

在使用 serialize() 函数快速获取表单数据时,必须为每个表单域添加 name 属性! 例如下面的示例中,只能通过 serialize() 函数获取到密码的值:

serialize() 函数的其他特点

该方法是jQuery封装的,使用时必须引入jQuery 使用serialize(),各表单域必须有 name 属性 使用该方法得到的结果是一个查询字符串结构:name=value&name=value 该方法 能够 获取 隐藏域的值 该方法不能得到禁用状态的值 该方法不能得到文件域中的文件信息,所以不能完成文件上传

 <form>
      <input type="text" name="username" />
      <input type="text" name="password" />
      <input type="text" />
      <button type="button">获取表单数据</button>
    </form>
    <script src="./jquery.js"></script>
    <script>
      // 序列化
      // 把对象或者数组 转成 字符串格式  过程  序列化  JSON.stringify();
      // 把字符串格式 转成 对象或者数组    反序列化   JSON.parse()
      const button = document.querySelector('button');
​
      // 假设我想要使用 快速获取表单数据 序列化 功能
      // 1 直接用jq的 serialize
      // 2 es6 新的对象 用这些新的对象 构造自己的序列化 方法 - 没有演示
      // 3 传统- 自己写代码 获取每一个input标签的 自己写代码进行字符串拼接  没有演示
      // 讲解js基础 对象 数组 字符串 转来转去
​
      button.addEventListener('click', function () {
        // 使用jq的方法 获取表单的数据 (字符串)
​
        // username=11&password=22  get请求 两种传递参数的方式
        // 1 params对象
        // 2 在url上拼接字符串的形式 http:/api?username=11&password=22
        // const data = $("form").serialize();
        const data = myfunc('form'); // 不要这么做 人品坏
        console.log(data);
      });
​
      function myfunc(query) {
        return $(query).serialize();
      }
    </script>

FormData

FormData 是一个浏览器对象。用于管理表单数据。 IE10+支持。 可以这样理解,FormData的作用和 jQuery中的 serialize() 作用一样,用于快速收集表单数据 并且可以将创建的FormData对象直接提交给接口。

典型应用场景:FormData + Ajax 技术实现文件上传的功能。

FormData基本使用方法

假设需要收集 < form >……< /form > 里面的所有表单项的值 要求,每个表单元素都具有 name 属性

在提交数据前,可以使用下列API方法对数据进行查看和修改

1650974718891.png

FormDataserialize 的区别

共同点:

都需要设置表单各项的name属性。

都能快速收集表单数据

都能够获取到隐藏域(< input type="hidden" />)的值

都不能获取禁用状态(disabled)的值

不同点:

FormData属于原生的代码;serialiaze是jQuery封装的方法

FormData可以收集文件域(< input type="file"/>)的值,而serialize不能。如果有文件上传,则必须使用FormData

得到的结果的数据类型不一样(知道即可)

结合 FormData 实现头像上传

主要的实现步骤:

使用文件选择器选择图片文件

把用户选择的文件存入 FormData 对象

使用 axios 把 FormData 发送给服务器

模拟文件选择器的点击事件

演示

<img src="" alt="">
    <input type="file" accept="image/*">
    <script>
        /* 
      1 先允许用户选择本地的图片(很快 图片 上传视频)
        1 指定文件上传的类型 只能是图片不能是其他  input标签一个属性 指定上传的文件的类型 accept
          accept = "image/*"
          accept = "image/*,video/*"
          https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/Input/file#唯一文件类型说明符
​
        2 给input标签绑定 change事件 图片上传浏览器内存中 就会触发 
​
        3 this.files来获取文件数组
​
        4 可选 
          1 直接把文件开始上传
          1 先在网页显示一下用户选择的图片 - 来确定是不是一张 
      2 把图片上传到指定服务器 
        1 图片文件?axios
       */
​
        const img = document.querySelector('img')
        const input = document.querySelector('input')
        input.addEventListener('change', function () {
            console.log(this.files);
            const file = this.files[0] // 要上传的文件对象
            // 新的js对象 把浏览器内存中图片文件的地址 获取出来
            const src = URL.createObjectURL(file)
            console.log(src);
            // 让图片显示出来
            img.src = src
        })
    </script>

文件域补充

input标签的属性

文件域:< input type="file" />

accept 属性:控制能够选择的文件类型,比如 accept="image/png,image/jpeg"

multiple 属性:控制是否可以多选文件

文件对象

面向对象中,讲过,JS中表示一个人,需要用到对象。

JS中表示一个文件,也需要用对象,也就是文件对象

文件对象,是本地文件的一个表示。

通俗的说,在 JavaScript 中,使用 文件对象 表示一个本地文件。

文件对象不需要自己创建,可以通过文件域获取得到

选择一个或多个文件

根据文件域,找到它的 files 属性。files属性是一个伪数组,里面包含了一个或多个文件对象。

<img src="" alt="" />
    <input type="file" accept="image/*" />
    <script src="./lib/axios.js"></script>
    <script>
      /* 
      2 把图片上传到指定服务器 
        2 根据接口文档的要求来代码 
          url、请求类型、请求参数(重点)  
​
          url http://www.itcbc.com:3006/api/formdata
          method post 
          请求参数 上传文件 给后端的参数 肯定是 formdata 类型 
      
       */
      const input = document.querySelector('input');
      const img = document.querySelector('img');
      input.addEventListener('change', function () {
        const file = this.files[0];
        const src = URL.createObjectURL(file);
        img.src = src;
​
        // 参数名称 avatar  参数值 file
​
        const formdata = new FormData(); // 创建一个空formdata对象
        formdata.append('avatar', file); // 接口要求 把文件追加到 formdata对象
​
        // 把数据上传到服务器中 即可
        axios({
          method: 'post',
          url: 'http://www.itcbc.com:3006/api/formdata',
          data: formdata,
        }).then((result) => {
          console.log(result);
        });
​
        // 简写
        // axios
        //   .post('http://www.itcbc.com:3006/api/formdata', formdata)
        //   .then((result) => {
        //     console.log(result);
        //   });
      });
    </script>

axios 请求方法的别名(简写)

在实际开发中,常用的 5 种请求方式分别是: GET、POST、PUT、PATCH、DELETE

为了简化开发者的使用过程,axios 为所有支持的请求方法提供了别名:

axios.get(url, config)

axios.delete(url, config)

axios.post(url, data, config)

axios.put(url, data, config)

axios.patch(url, data, config)

简化方法的参数

为了查看方法,下面将这些方法对齐:

1650974165354.png

axios.get() 的用法

使用 axios.get() 可以方便快捷地发起 GET 请求

axios.post() 的用法

使用 axios.post() 可以方便快捷地发起 POST 请求

演示

<script>
        // axios.get()   直接发送get请求
      // axios.post()  直接发送post请求
      // axios.delete()   直接发送delete请求
      // axios.put()    直接发送put请求
      // console.dir(axios);
​
      // get 请求
      // axios.get(Url)
      // axios.get(Url,{params:{参数}})  ;
​
      axios.get('http://www.itcbc.com:3006/api/getbooks?appkey=lin123')
      .then(result=>{
        console.log(result);
        })
​
        // post请求
      // axios.post(url,参数(对象));
      // axios.post(url,参数(字符串格式));
        // 第一种
    //   axios
    //     .post('http://www.itcbc.com:3006/api/addbook', {
    //       bookname: 'post请求1',
    //       author: 'post请求222',
    //       publisher: 'post请求33',
    //       appkey: 'lin123',
    //     }).then((result) => {
    //       console.log(result);
    //     });
​
        // 第二种
        // 创建变量
        const url = 'http://www.itcbc.com:3006/api/addbook'
        const query = 'bookname=111222&author=222222&publisher=33333&appkey=lin123';
        axios.post(url, query).then((result)=>{
            console.log(result);
        })
        // 第三种
        // axios.post('http://www.itcbc.com:3006/api/addbook', 'bookname=111222&author=222222&publisher=33333&appkey=lin123').then((result)=>{
        //     console.log(result);
        // })
    </script>

1650974165354.png

拦截器

拦截器(interceptors)用来全局拦截 axios 的每一次请求与响应

好处:可以把每个请求中,某些重复性的业务代码封装到拦截器中,提高代码的复用性。

1650974459296.png

需要在每个请求中分别展示和隐藏 loading 效果。示例代码如下:

1650974497679.png

拦截器案例

<img src="./20200527152202778.gif" alt="">
    <button>发送请求</button>
    <script src="../../JS/axios.js"></script>
    <script>
        // 添加请求拦截器
        axios.interceptors.request.use(function (config) {
            // 在发送请求之前做些什么
            document.querySelector('img').style.display = 'block';
            return config;
        }, function (error) {
            // 对请求错误做些什么
            return Promise.reject(error);
        });
​
        
​
        // 添加响应拦截器
      axios.interceptors.response.use(
        function (response) {
          document.querySelector('img').style.display = 'none';
          return response;
        },
        function (error) {
          // 超出 2xx 范围的状态码都会触发该函数。
          // 对响应错误做点什么
          return Promise.reject(error);
        }
      );
​
      const button = document.querySelector('button');
      button.addEventListener('click', function () {
        // 发送网络请求
        axios
          .get('http://www.itcbc.co:3006/api/getbooks?appkey=wanshao1234')
          .then((result) => {
            console.log(result);
          });
      });
    </script>

请求报文 & 响应报文

什么是请求报文和响应报文

客户端与服务器通信的过程是基于请求响应的。其中:

请求报文规定了客户端以什么格式把数据发送给服务器

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

请求报文 - 格式

请求报文请求行(request line)、请求头部( header )、空行请求体 4 个部分组成。图示如下:

1651147087302.png

注意:

在浏览器中,GET 请求比较特殊,它只有请求头,没有请求体

在浏览器中,POST、PUT、PATCH、DELETE 请求既有请求头,又有请求体。

响应报文 - 格式

响应报文状态行响应头部空行响应体 4 个部分组成。图示如下:

1651147200140.png

URL参数

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

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

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

/api/xxx?参数=值&参数=值 (这种格式的字符串叫做查询字符串,所以这样的参数叫做查询参数)

/api/xxx/值/值 (Restful 风格的接口用这种格式的参数)

请求体

除GET请求以外,其他4种常用的请求方式,都可以设置请求体。

请求体的大小没有限制,所以可以提交大量的数据

常用的请求体格式有如下三种:

参数=值&参数=值 (查询字符串格式)

'{ "id": 1, "name": "zs" }' (JSON格式)

new FormData() (FormData对象格式)

axios中,如何设置不同格式的请求体

第一种格式:参数=值&参数=值

1651147531342.png

第二种格式: '{ "id": 1, "name": "zs" }'

1651147563638.png

第三种格式: new FormData()

1651147591346.png

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

1651147769479.png

使用axios就不用关心这个请求头了,因为axios已经帮我们处理好了加请求头这件事

不过写原生代码,就需要自己指定了

http 响应状态码

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

1651147829066.png

常见的 http 响应状态码

1651147852808.png

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

正确区分响应状态码和业务状态码的不同,是保证使用 Ajax 不迷茫的必要前提。从如下 3 个方面进行区分: 所处的位置 表示的结果 通用性

  1. 所处的位置不同: 在响应头的状态行中所包含的状态码,或者请求列表中的Status,叫做“响应状态码

1651147950659.png

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

1651148052410.png

  1. 表示的结果不同: 响应状态码只能表示这次请求的成功与否(成功地失败了)

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

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

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

1651148124825.png