十二.http&Ajax&Axios前后端通信

·  阅读 1211

第一部分:前后端交互与HTTP

1.前后端通信

1.1 什么是前后端通信?

前后端通信是指浏览器和服务器之间数据交互(请求-响应)的过程:前端向后端发送请求数据,后端接收到前端的请求之后,响应数据请求

  • 前端向后端发送数据(用户注册):浏览器把用户注册信息以表单形式提交,点击注册后传输给服务器,服务器进行处理
  • 后端向前端发送数据(访问页面):用户输入网址按下回车之后,请求一些资源加载,后端返回服务器的资源,让浏览器渲染

1.2 前后端通信方式(三种)

1.使用浏览器访问页面进行通信

在浏览器地址栏输入网址,按下回车

2.HTML 的标签进行通信

浏览器在解析 HTML 标签的时候,遇到一些特殊的标签(link/img/script/iframe),会再次向服务器发送请求
(如果过有很多这样的标签要一个一个请求吗?chrom会允许同一域名下一次六个并发请求,所以要把这些标签里面的资源放到不同域名下增加请求效率)

还有一些标签,浏览器解析的时候,不会向服务器发送请求,但是用户可以使用他们向服务器发送请求如 a/form

3.Ajax 和 Fetch

2.HTTP协议

2.1什么是http协议?

  • 全称(HyperText Transfer Protocol)超文本传输协议
  • 超文本:原先一个个单一的文本,通过超链接将其联系起来。由原先的单一的文本变成了可无限延伸、扩展的超级文本、立体文本
  • HTML、JS、CSS、图片、字体、音频、视频等等文件,都是通过 HTTP(超文本传输协议) 在服务器和浏览器之间传输
  • 每一次前后端通信,前端需要主动向后端发出请求,后端接收到前端的请求后,可以给出响应

2.2 HTTP 浏览器渲染过程(图解)

1.png

2.3 HTTP报文

  • 浏览器向服务器发送请求时,请求本身就是信息,叫请求报文;
  • 服务器向浏览器发送响应时传输的信息,叫响应报文;

11111.jpg

1.jpg

HTTP 报文格式
       请求
       请求头:起始行+首部
       请求体

      // GET 请求,没有请求体,数据通过请求头携带
      // POST 请求,有请求体,数据通过请求体携带

       响应
       响应头:起始行+首部
       响应体
复制代码

2.4 常用HTTP方法(增删改查)

http方法用来定义对于资源采取什么样的操作的,有各自的语义,浏览器发送请求时采用的方法,和响应无关

  • 1.GET 获取数据

    • GET 通过地址在请求头中携带数据
    • 能携带的数据量和地址的长度有关系,一般最多就几K
    • GET通过请求头也就是url发送数据, 可以被缓存
    • 不安全 url?username=alex GET的数据在URL中,通过历史记录,缓存很容易查到数据信息。
    • GET无害: 刷新、后退等浏览器操作GET请求是无害的,
  • 2.POST 创建数据(注册)

    向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。

    • POST 既可以通过地址在请求头中携带数据,也可以通过请求体携带数据
    • 能携带的数据量理论上是无限的
    • POST一般通过请求体发送数据, 所以不会被缓存
    • POST的数据因为在请求主体内,不会被缓存,所以有一定的安全性保证
    • POST可能重复提交表单
  • 3.PUT 更新数据(修改个人信息,修改密码)

    从客户端向服务器传送的数据取代指定的文档的内容。如更新一篇文章

  • 4.DELETE 删除数据(删除一条评论)

    请求服务器删除指定的页面。

  • 5.RESTful 接口设计

一种接口设计风格,充分利用 HTTP 方法的语义,比如设置用户接口,增删改查的接口都是一样的,但是后端可以根据你的请求方式判断你对应的操作

2.5 常用HTTP状态码

HTTP 状态码是定义服务器对请求的处理结果,是服务器返回的。

  • 100~199 消息:代表请求已被接受,需要继续处理 // websocket
  • 100 客户必须继续发出请求
  • 101 客户要求服务器根据请求转换HTTP协议版本
  • 200~299 成功
  • 200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
  • 201 (已创建) 请求成功并且服务器创建了新的资源。
  • 202 (已接受) 服务器已接受请求,但尚未处理。
  • 300~399 重定向:给你返回一个新的请求地址,你需要用新的地址重新发送请求
  • 301 Moved Permanently
  • 302 Move Temporarily 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
  • 304 Not Modified(没有被修改你可以继续使用)
  • 400~499 请求错误
  • 400 (错误请求) 服务器不理解请求的语法。
  • 401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
  • 403 (禁止) 服务器拒绝请求。
  • 404 Not Found(请求代码写的有问题)
  • 500~599 服务器错误(服务端搞错了)
  • 500 Internal Server Error

第二部分:本地存储

1.Cookie

  • Cookie (HTTP Cookie),是浏览器存储数据在用户本地的一种方式, 一般会自动随着浏览器每次请求发送到服务器端
  • 利用 Cookie 跟踪统计用户访问该网站的习惯,比如什么时间访问,访问了哪些页面,在每个网页的停留时间等
  • 在浏览器中操作 Cookie,不要在 Cookie 中保存密码等敏感信息.

2.Cookie的基本用法(代码中设置、读取)

2.1.写入 Cookie(不能一起设置,只能一个一个设置)

       document.cookie = 'username=zs';
       document.cookie = 'age=18';
复制代码

2.2.读取 Cookie

读取的是一个由名值对构成的字符串,每个名值对之间由“; ”(一个分号和一个空格)隔开

      console.log(document.cookie);
      // username=zs; age=18
复制代码

3.Cookie的属性

3.1 Cookie 的名称(Name)和值(Value)

  • 最重要的两个属性,创建 Cookie 时必须填写,其它属性可以使用默认值
  • Cookie 的名称或值如果包含非英文字母,则写入时需要使用 encodeURIComponent() 编码,读取时使用 decodeURIComponent() 解码
      document.cookie = `username=${encodeURIComponent('张三')}`;
      document.cookie = `${encodeURIComponent('用户名')}=${encodeURIComponent(
        '张三'
      )}`;
复制代码

3.2 失效(到期)时间

  • 对于失效的 Cookie,会被浏览器清除
  • 如果没有设置失效(到期)时间,这样的 Cookie 称为会话 Cookie,它存在内存中,当会话结束,也就是浏览器关闭时,Cookie 消失
  • 想长时间存在,设置 Expires 或 Max-Age
// expires属性,值为 Date 类型
      document.cookie = `username=alex; expires=${new Date(
        '2100-1-01 00:00:00'
     )}`;
 // max-age值为数字,表示当前时间 + 多少秒后过期,单位是秒
 // 如果 max-age 的值是 0 或负数,则 Cookie 会被删除
      document.cookie = 'username=alex; max-age=5';
      document.cookie = `username=alex; max-age=${24 * 3600 * 30}`;
复制代码

3.3 Domain 域

Domain 限定了访问 Cookie 的范围(不同域名) 使用 JS 只能读写当前域或父域的 Cookie,无法读写其他域的 Cookie

       document.cookie = 'username=alex; domain=www.imooc.com';
复制代码

3.4 Path 路径

Path 限定了访问 Cookie 的范围(同一个域名下) 使用 JS 只能读写当前路径和上级路径的 Cookie,无法读写下级路径的 Cookie

       document.cookie = 'username=alex; path=/course/list';
       document.cookie = 'username=alex; path=/1.Cookie/';

      // 当 Name、Domain、Path 这 3 个字段都相同的时候,才是同一个 Cookie
复制代码

3.5HttpOnly

设置了 HttpOnly 属性的 Cookie 不能通过 JS 去访问

3.6 Secure 安全标志

Secure 限定了只有在使用了 https 而不是 http 的情况下才可以发送给服务端
Domain、Path、Secure 都要满足条件,还不能过期的 Cookie 才能随着请求发送到服务器端

4.Cookie的封装

在cookie.js里封装一个cookie,向外提供三个方法,set,get,remove设置获取删除

 // import { set, get, remove } from './cookie.js';其他地方引入cookie方法
// 1.写入 Cookie的方法:
const set = (name, value, { maxAge, domain, path, secure } = {}) => {
  let cookieText = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;

  if (typeof maxAge === "number") {
    cookieText += `; max-age=${maxAge}`;
  }

  if (domain) {
    cookieText += `; domain=${domain}`;
  }

  if (path) {
    cookieText += `; path=${path}`;
  }

  if (secure) {
    cookieText += `; secure`;
  }

  document.cookie = cookieText;

  // document.cookie='username=alex; max-age=5; domain='
};

// 2.get方法通过 name 获取 cookie 的值
const get = (name) => {
  name = `${encodeURIComponent(name)}`;

  const cookies = document.cookie.split("; ");

  for (const item of cookies) {
    const [cookieName, cookieValue] = item.split("=");

    if (cookieName === name) {
      return decodeURIComponent(cookieValue);
    }
  }

  return;
};
// get('用户名');获取

// remove方法根据 name、domain 和 path 删除 Cookie
const remove = (name, { domain, path } = {}) => {
  set(name, "", { domain, path, maxAge: -1 });
};

export { set, get, remove };
复制代码

在其他文件中使用cookie.js

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Cookie 的封装</title>
  </head>
  <body>
    <script type="module">
      import { set, get, remove } from './cookie.js';
//设置cookie名值
       set('age', 18);
       set('用户名', '张三');
       set('sex', 'male', {
         maxAge: 30 * 24 * 3600
       });
       
//获取cookie
       get('sex');
       
//删除cookie
       remove('username');
       remove('用户名');
    </script>
  </body>
</html>
复制代码

5. localStorage

  • localStorage 也是一种浏览器存储数据的方式(本地存储),它只是存储在本地,不会发送到服务器端。
  • 一种持久化的存储方式,也就是说如果不手动清除,数据就永远不会过期。它是采用键值对的方式存储数据,按域名将数据分别保存到对应数据库文件里。相比 Cookie 来说,它能保存更大的数据。
  • sessionStorage 是一种会话级别的缓存,关闭浏览器时数据会被清除。需要注意的是 sessionStorage 的作用域是窗口级别的,也就是说不同窗口之间保存的 sessionStorage 数据是不能共享的。sessionStorage 的数据只存在于当前浏览器的标签页;

localStorage 的特点:

大小限制为 5MB ~10MB;
在同源的所有标签页和窗口之间共享数据;
数据仅保存在客户端,不与服务器进行通信;
数据持久存在且不会过期,重启浏览器后仍然存在;
对数据的操作是同步的。

5.1 localStorage方法:
// 通过setItem()增加一个数据项
localStorage.setItem('myName', 'Semlinker');

// 通过getItem()获取某个数据项
// 获取不存在的返回 null
let me = localStorage.getItem('myName');

// 通过removeItem()移除某个数据项
// 删除不存在的 key,不报错
localStorage.removeItem('myName');

// 移除所有数据项
localStorage.clear();
复制代码
5.1 localStorage的键值:

localStorage 存储的键和值只能是字符串类型,不是字符串类型,也会先转化成字符串类型再存进去

第三部分 Ajax基础

1.什么是Ajax?

Ajax 是 Asynchronous JavaScript and XML(异步 JavaScript 和 XML)的简写.

  • Ajax 中的异步:可以异步地向服务器发送请求,在等待响应的过程中,不会阻塞当前页面,浏览器可以做自己的事情。直到成功获取响应后,浏览器才开始处理响应数据
  • XML(可扩展标记语言)是前后端数据通信时传输数据的一种格式,XML 现在已经不怎么用了,现在比较常用的是 JSON
  • Ajax 其实就是浏览器与服务器之间的一种异步通信方式
  • 使用 Ajax 可以在不重新加载整个页面的情况下,对页面的某部分进行更新

实例 ① 慕课网注册检测 ;② 慕课网搜索提示

2.搭建 Ajax 开发环境

Ajax 需要服务器环境,非服务器环境下,很多浏览器无法正常使用 Ajax;
vscode中安装插件Live Server就可以快速搭建服务器环境

3.Ajax 的使用步骤

Ajax 想要实现浏览器与服务器之间的异步通信,需要依靠 XMLHttpRequest,它是一个构造函数. 发送Ajax请求核心四部曲:

  • 1.创建一个XMLHttpRequest实例对象。
  • 2.打开请求连接,配置请求信息。
  • 3.监听请求状态——不同的状态做不同的事。
  • 4.发送AJAX请求,AJAX任务开始,一直到响应主体信息返回代表任务结束。

3.1.创建XMLHttpRequest实例对象

       const xhr = new XMLHttpRequest();
复制代码

3.2.打开请求连接,配置请求信息

调用 open 并不会真正发送请求,而只是做好发送请求前的准备工作

xhr.open('GET','url',true)
有三个参数:第一个参数为http请求方式:GET、POST、PUT、DELETE
           第二个参数为请求地址
           第三个参数为是否为异步请求,true表示是异步请求   
复制代码

3.3.监听事件,处理响应

当获取到响应后(readyState 改变),会触发 xhr 对象的 readystatechange 事件,可以在该事件中对响应进行处理判断请求状态是否完成,并且请求是否成功了

AJAX状态码——xhr.readyState
HTTP状态码——xhr.status
readystatechange 事件监听 readyState 这个状态的变化,它的值从 0 ~ 4,一共 5 个状态:

0:未初始化。尚未调用 open()
1:启动。已经调用 open(),但尚未调用 send()
2:发送。已经调用 send(),但尚未接收到响应
3:接收。已经接收到部分响应数据
4:完成。已经接收到全部响应数据,而且已经可以在浏览器中使用了
复制代码
      xhr.onreadystatechange = () => {
      // 4:完成。已经接收到全部响应数据,而且已经可以在浏览器中使用了
        if (xhr.readyState !== 4) return;
        
      //200-299:成功,请求被成功接收并处理;
      //304:Not Modified 未修改。返回此状态码时,不会返回任何资源,而是让浏览器去获取缓存中的资源。
        if ((xhr.status >= 200) & (xhr.status < 300) || xhr.status === 304) {
          // console.log('正常使用响应数据');
          console.log(xhr.responseText);
        }
      };
复制代码

或者:

       xhr.addEventListener('readystatechange', () => {......}, fasle);
复制代码
  • 为了兼容性,readystatechange 中不使用 this,而是直接使用 xhr
  • 由于兼容性的原因,最好放在 open 之前

3.4.发送请求

//  send() 的参数是通过请求体携带的数据,所以GET请求的send方法不传参或传null
xhr.send(null);
复制代码

4.使用 Ajax 完成前后端通信-小案例

      const url = 'https://www.imooc.com/api/http/search/suggest?words=js';

      const xhr = new XMLHttpRequest();
      xhr.onreadystatechange = () => {
        if (xhr.readyState !== 4) return;

        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
          console.log(xhr.responseText);
          console.log(typeof xhr.responseText);
         //XMLHttpRequest.responseText 在一个请求被发送后,从服务器端返回文本。
        }
      };
      xhr.open('GET', url, true);
      xhr.send(null);
复制代码

5.ajax的GET请求

1.携带数据
      GET 请求不能通过请求体携带数据,但可以通过请求头携带
      const url =
        'https://www.imooc.com/api/http/search/suggest?words=js&username=alex&age=18';

2.数据编码
      如果携带的数据是非英文字母的话,比如说汉字,就需要编码之后再发送给后端,不然会造成乱码问题
      可以使用 encodeURIComponent() 编码

      const url = `https://www.imooc.com/api/http/search/suggest?words=${encodeURIComponent(
        '前端'
      )}`;
复制代码

6.ajax的POST请求

1.携带数据
      POST 请求主要通过请求体携带数据,同时也可以通过请求头携带

      如果想发送数据,直接写在 send() 的参数位置,一般是字符串
      xhr.send('username=alex&age=18');

      不能直接传递对象,需要先将对象转换成字符串的形式
      xhr.send({
        username: 'alex',
        age: 18
      });
复制代码

7.JSON

JSON是Ajax 发送和接收数据的一种格式(前端认识,后端也认识) JSON 有 3 种形式,每种形式的写法都和 JS 中的数据类型很像,可以很轻松的和 JS 中的数据类型互相转换

7.1 JSON的三种形式

  • 1.简单值形式xxx.json

JSON 的简单值形式就对应着 JS 中的基础数据类型: 数字、字符串、布尔值、null

注意事项
      ① JSON 中没有 undefined 值
      ② JSON 中的字符串必须使用双引号
      ③ JSON 中是不能注释的
复制代码
  • 2.对象形式

JSON 的对象形式就对应着 JS 中的对象

注意事项:
      JSON 中对象的属性名必须用双引号,属性值如果是字符串也必须用双引号
      JSON 中只要涉及到字符串,就必须使用双引号
      不支持 undefined
复制代码
  • 3.数组形式

JSON 的数组形式就对应着 JS 中的数组

      [1, "hi", null]
 注意事项:
      数组中的字符串必须用双引号
      JSON 中只要涉及到字符串,就必须使用双引号
      不支持 undefined
复制代码

7.2 两种JSON的基本用法

1. JSON.parse() 可以将 JSON 格式的字符串解析成 JS 中的对应值

一定要是合法的 JSON 字符串,否则会报错

2.JSON.stringify()可以将 JS 的基本数据类型、对象或者数组转换成 JSON 格式的字符串

     xhr.send(JSON.stringify({
         username: 'alex',
         age: 18
       }))
复制代码

7.3 JSON封装localStorage

localStorage里面的键和值是字符串,但是有的时候我们想传一些数组对象,可以封装一下:

const storage = window.localStorage;
// 设置
const set = (key, value) => {
  // {
  //   username: 'alex'
  // }
  storage.setItem(key, JSON.stringify(value));
};

// 获取
const get = key => {
  // 'alex'
  // {
  //   "username": "alex"
  // }
  return JSON.parse(storage.getItem(key));
};

// 删除
const remove = key => {
  storage.removeItem(key);
};

// 清空
const clear = () => {
  storage.clear();
};

export { set, get, remove, clear };
复制代码

第四部分 跨域

  • 跨域就是不同域之间发送请求;
  • 不同域协议、域名、端口号,任何一个不一样,就是不同域;
  • 同源策略是浏览器的一种安全策略,阻止跨域请求.

跨域解决方案: ① CORS 跨域资源共享 ② JSONP
优先使用 CORS 跨域资源共享,如果浏览器不支持 CORS 的话,再使用 JSONP

1.跨域的第一种方案:CORS跨域资源共享(后端要做的 IE10)

后端在响应头设置:允许跨域
 Access-Control-Allow-Origin: *   // 表明允许所有的域名来跨域请求它    
 Access-Control-Allow-Origin: http://127.0.0.1:5500  // 只允许指定域名的跨域请求

CORS 跨域的过程
      ① 浏览器发送请求
      ② 后端在响应头中添加 Access-Control-Allow-Origin 头信息
      ③ 浏览器接收到响应
      ④ 如果是同域下的请求,浏览器不会额外做什么,这次前后端通信就圆满完成了
      ⑤ 如果是跨域请求,浏览器会从响应头中查找是否允许跨域访问
      ⑥ 如果允许跨域,通信圆满完成
      ⑦ 如果没找到或不包含想要跨域的域名,就丢弃响应结果
复制代码

2.跨域的第二种方案: Jsonp

JSONP 的原理:script 标签跨域不会被浏览器阻止,JSONP 主要就是利用 script 标签,加载跨域文件。

使用 JSONP 实现跨域:

1.后端创建一个接口,注意后面的aaaa是前端随便定义的:`https://www.imooc.com/api/http/jsonp?callback=aaaa`
2.这个接口打开的数据是这样的,以函数调用形式传输数据:
      aaaa(
        { "code": 200,
         "data": [ 
           { "word": "jsp" }, 
           { "word": "js" }, 
           { "word": "json" }, 
           { "word": "js 入门" }, 
           { "word": "jstl" } ] 
          }
          );
3.前端只需要在script标签里面引入这个接口,然后根据我们在接口自己定义的callback=aaaa声明一个aaaa函数
4.当发送请求时就调用了这个函数,把数据通过函数调用传递过来
复制代码
/*
服务器端准备好 JSONP 接口:
   https://www.imooc.com/api/http/jsonp?callback=handleResponse
*/
/*
前端手动加载 JSONP 接口或动态加载 JSONP 接口
*/
  const script = document.createElement('script');
  script.src ='https://www.imooc.com/api/http/jsonp?callback=handleResponse';
  document.body.appendChild(script);

//声明函数
      const handleResponse = data => {
        console.log(data);//拿到数据了
      };
//相当于通过函数执行传递参数给函数,函数内部获取数据
复制代码

第五部分 XMLHttpRequest对象

1. XMLHttpRequest属性

1.responseType:表示文本形式的响应内容:

  • responseType是在准备好发送和发送之前设置
  • responseType 没有设置时候,responseText和response一样,相当于xhr.responseType='text'
  • responseType设置为json之后,就需要使用response属性获取了;
  • 知道后端返回来的格式是json,设置json了,就不需要编译了,系统自动编译;

2.timeout 属性:设置请求的超时时间(单位 ms)xhr.timeout = 10000; 3.withCredentials 属性:指定使用 Ajax 发送请求时是否携带 Cookie

使用 Ajax 发送请求,默认情况下,同域时,会携带 Cookie;跨域时,不会 xhr.withCredentials = true; 最终能否成功跨域携带 Cookie,还要看服务器同不同意

2. XMLHttpRequest方法

1.abort()
      终止当前请求
      一般配合 abort 事件一起使用

2.setRequestHeader()
       可以设置请求头信息,只有发送post请求时,才有必要设置这个属性
       xhr.setRequestHeader(头部字段的名称, 头部字段的值);

       xhr.setRequestHeader('Content-Type', 'application/json');
      // 请求头中的 Content-Type 字段用来告诉服务器,浏览器发送的数据是什么格式的
     
     1.发送json数据
      xhr.setRequestHeader('Content-Type', 'application/json');//浏览器发送的是json数据
      xhr.send(
        JSON.stringify({
          username: 'alex'
        })
      );

      2.发送名值对数据
      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
      xhr.send('username=alex&age=18');

//若果这样做报错了,就让后端改接口
复制代码

3. XMLHttpRequest事件

3.1.load 事件- 响应数据可用时触发

load事件可以替代xhr.onreadystatechange事件,只需监听响应(xhr.status)是否成功,不需要监听请求(readyState)是否成功。

xhr.addEventListener(
        'load',
        () => {
          if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
            console.log(xhr.response);
          }
        },
        false
      );
//不支持ie6-8
复制代码

3.2.error 事件-请求发生错误时触发(如同地址错误,压根就没有发出请求)

xhr.addEventListener(
        'error',
        () => {
          console.log('error');
        },
        false
      );
复制代码

3.3.abort 事件-调用 abort() 终止请求时触发(ie10+)

3.4.timeout 事件-请求超时后触发(ie8+)

第六部分 Ajax进阶

1.FormData

使用 Ajax 提交表单的时候,我们会用到FormData;
FormData 的基本用法:

//通过 HTML 表单元素创建 FormData 对象
      const fd = new FormData(表单元素);
      xhr.send(fd);
//通过 append() 方法添加数据
      const fd = new FormData(表单元素);
      fd.append('age', 18);
      fd.append('sex', 'male');
      xhr.send(fd);

      IE10 及以上可以支持
复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>FormData</title>
  </head>
  <body>
    <form
      id="login"
      action="https://www.imooc.com/api/http/search/suggest?words=js"
      method="POST"
      enctype="multipart/form-data"
    >
      <input type="text" name="username" placeholder="用户名" />
      <input type="password" name="password" placeholder="密码" />
      <input id="submit" type="submit" value="登录" />
    </form>
    <script>
      const login = document.getElementById('login');
      const { username, password } = login;
      const btn = document.getElementById('submit');
      const url = 'https://www.imooc.com/api/http/search/suggest?words=js';

      btn.addEventListener(
        'click',
        e => {
          // 阻止表单自动提交
          e.preventDefault();

          // 表单数据验证

          // 发送 Ajax 请求
          const xhr = new XMLHttpRequest();

          xhr.addEventListener(
            'load',
            () => {
              if (
                (xhr.status >= 200 && xhr.status < 300) ||
                xhr.status === 304
              ) {
                console.log(xhr.response);
              }
            },
            false
          );
          xhr.open('POST', url, true);
          // 收集表单数据
          const data = new FormData(login);
                    console.log(data); //直接打印不出来
                   for (item of data) {
                          console.log(item);
                        }
                   /*
                        ["username", "1231"]
                        ["password", "21313131"]
                   */
          xhr.send(data);
        },
        false
      );
    </script>
  </body>
</html>
复制代码

2.Ajax封装

// 工具函数-把对象变成字符串(序列化)
  /* 对象变成数组,数组变成字符串
   对象不能遍历,利用Object.entries()
   Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)

*/
//数据序列化成urlencoded格式的字符串
const serialize=param=>{
    const results=[];
    for(const [key,value] of Object.entries(param)){
        results.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
    }
//['username=alex','age=18']

//join() 方法用于把数组中的所有元素放入一个字符串。
   return results.join("&")

}
复制代码
给url添加参数
//www.muke.com
//www.muke.com?words=js
//www.muke.com?words=js&
const addURLData=(url,data)=>{
if(!data) return '';
const mark=url.includes('?')?'&':'?'

return `${mark}${data}`
}

复制代码

第一步:封装:ajax函数封装在ajax.js里面了

//第一步:默认参数设置:
const DEFAULTS = {
  method: "GET",
  //请求头携带的数据
  params: null,
  //   params: {
  //     username: "alex",
  //     age: 14,
  //   },
  //会自动转化为:username=alex&age=18

  //请求体携带的数据
  data: null,
  //   data: {
  //     username: "alex",
  //     age: 14,
  //   },
  //data:FormData数据

  contentType: "application/x-www-form-urlencoded",
  responseType: "",
  timeoutTime: 0,
  withCredentials: false,

  //方法:
  //成功的方法
  success() {},
  //   状态码异常处理
  httpCodeError() {},
  //出现错误,比如地址不对压根没有发出去
  error() {},
  //中止了
  abort() {},
  //超时了
  timeout() {},
};
//第二步:创建Ajax类
class Ajax {
  constructor(url, options) {
//外界传来的url地址
    this.url = url;
//默认参数设置
    this.options = Object.assign({}, DEFAULTS, options);
    //1.初始化,这里面进行四部曲操作,让代码不那么拥挤
    this.init();
  }
  init() {
    const xhr = new XMLHttpRequest();
    //绑定到类的共有属性
    this.xhr = xhr;

    //2.把监听方法写到里面
    this.bindEvents();

    // 3.处理xhr.open('POST', url, true);
    xhr.open(this.options.method, this.url + this.addParam(), true);
    //4.设置responseType
    this.setResponseType();
    //5.设置跨域是否携带cookie
    this.setCookie();
    //5.设置超时
    this.timeout();
    //6.发送请求 xhr.send();
    this.sendData();
  }

  //绑定响应事件处理程序的区域
  bindEvents() {
  //偷懒
    xhr = this.xhr;
    //把方法结构出来在这里面调用
    const { success, httpCodeError, error, abort, timeout } = this.options;
    xhr.addEventListener(
      "load",
      () => {
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
          success(xhr.response, xhr);
        } else {
          httpCodeError(xhr.status, xhr);
        }
      },
      false
    );
    
    // error
    // 当请求遇到错误时,将触发 error 事件
    xhr.addEventListener(
      "error",
      () => {
        error(xhr);
      },
      false
    );

    // abort
    xhr.addEventListener(
      "abort",
      () => {
        abort(xhr);
      },
      false
    );

    // timeout
    xhr.addEventListener(
      "timeout",
      () => {
        timeout(xhr);
      },
      false
    );
  }
//下面是工具函数库
  //在地址上添加数据,就是`url?name=zs`
  /* 
  要先借用两个函数:
  先序列化函数,转化成'username=alex&age=18';
  再addURLData:统一数据格式加&还是❓
  */
  serialize(param) {
    const results = [];
    /*
    若果是对象就Object.entries(param)弄成二维数组然后用for..of遍历
    若果是数组就直接遍历了
    */
    for (const [key, value] of Object.entries(param)) {
      results.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
    }
    //处理之后变成这样了['username=alex','age=18']
    return results.join("&");
    //处理之后变成'username=alex&age=18'了
  }
  addURLData = (url, data) => {
    if (!data) return "";
    //有数据加&,没数据加?
    const mark = url.includes("?") ? "&" : "?";

    return `${mark}${data}`;
  };
  //   上面两个工具函数都是为他服务的;
  addParam() {
  //解构参数
    const { params } = this.options;
    if (!params) return "";
    return addURLData(this.url, serialize(params));
  }

  //设置responseType
  setResponseType() {
    this.xhr.responseType = this.options.responseType;
  }
  //   设置跨域是否携带cookie
  setCookie() {
    if (this.options.withCredentials) this.xhr.withCredentials = true;
  }
  //   设置超时
  setTimeout() {
    const { timeoutTime } = this.options;
    if (timeoutTime > 0) this.xhr.timeout = timeoutTime;
  }
  //发送数据
  sendData() {
    const xhr = this.xhr;
    //若果不需要再send中携带数据,直接发送
    if (!this.isSendData()) return xhr.send(null);

    //发送数据xhr.send(数据)
    let resultData = null;
    
    //// 发送FormData数据,content-type不需要设置,自动添加
    if (this.isFormData()) {
      resultData = data;
      
     // //是不是名值对格式的:username=alex&age=18
    } else if (this.isFormURLEncodedData()) {
      // 设置contentType
      this.setContentType("application / x - www - form - urlencoded");
      //发送这种格式的数据application / x - www - form - urlencoded
      resultData = this.serialize(data);
    } else if (this.isJsonData()) {
      // 设置contentType
      this.setContentType("application /json");
      resultData = this.serializeJson(data);
    } else {
      //其他格式
      this.setContentType();
      resultData = data;
    }
    xhr.send(resultData);
  }
  //是否需要在send中携带数据
  isSendData() {
    //data是请求体携带的数据
    const { data, method } = this.options;
    //如果data不存在返回false,上级函数直接return xhr.send(null);
    if (!data) return false;
    //若果是get请求,传不传都没用,返回false
    if (method.toLowerCase() === "GET".toLowerCase()) return false;
    return true;
  }

  ////判断是不是formdata数据,是就进行处理
  isFormData() {
    return this.options.data instanceof FormData;
  }
  ////判断是不是名值对格式的数据
  isFormURLEncodedData() {
    return this.options.contentType
      .toLowerCase()
      .includes("application / x - www - form - urlencoded");
  }
////判断是不是json格式的数据
  isJsonData() {
    return this.options.contentType.toLowerCase().includes("application/json");
  }
  ////转化为json格式的字符串
  serializeJson(param) {
    return JSON.stringify(param);
  }
  setContentType(contentType = this.options.contentType) {
    if (!contentType) return;
    this.xhr.setRequestHeader("Content-Type", contentType);
  }
  //获取XHR对象
  getXHR() {
    return this.xhr;
  }
}

export default Ajax;
复制代码

第二步:创建一个index.js实例化几个方法供外界使用

import Ajax from ./ajax.js;

const ajax=(url,options)=>{
   return new Ajax(url,options).getXHR()
}
//定义get请求,覆盖用户传过来的参数
const get=(url,options)=>{
    return ajax(url,{...options,method:'GET'})
}
//定义get请求发送json数据,覆盖用户传过来的参数
const getJSON=(url,options)=>{
    return ajax(url,{...options,responseType:'json'})
}
//post请求
const post=(url,options)=>{
    return ajax(url,{...options,method:'POST'})
}
export {
    ajax,get,getJSON,post
}
复制代码

第三步:模拟发送请求

<script>
import {ajax,get,getJSON,post} from './index.js'
 const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
      const xhr = ajax(url, {
        method: 'GET',
        params: { username: 'alex' },
        data: {
          age: 18
        },
        responseType: 'json',
        // timeoutTime: 10,

        success(response) {
          console.log(response);
        },
        httpCodeError(err) {
          console.log('http code error', err);
        },
        error(xhr) {
          console.log('error', xhr);
        },
        abort(xhr) {
          console.log('abort', xhr);
        },
        timeout(xhr) {
          console.log('timeout', xhr);
        }
      });

      xhr.abort();
<script/>
复制代码

3.使用promise封装ajax

import Ajax from "./ajax.js";

const ajax = (url, options) => {
  // return new Ajax(url, options).getXHR();
  let xhr;
  const p = new Promise((resolve, reject) => {
    xhr = new Ajax(url, {
      ...options,
      ...{
        success(response) {
          resolve(response);
        },
        httpCodeError(status) {
          reject({
            type: "ERROR_HTTP_CODE",
            text: `${status}`,
          });
        },
        error() {
          reject({
            type: "ERROR_REQUEST",
            text: "请求错误",
          });
        },
        abort() {
          reject({
            type: "ERROR_ABORT",
            text: "取消发送",
          });
        },
        timeout() {
          reject({
            type: "ERROR_TIMEOUT",
            text: "请求超时",
          });
        },
      },
    }).getXHR();
  });

  p.xhr = xhr;

  return p;
};

const get = (url, options) => {
  return ajax(url, { ...options, method: "GET" });
};

const getJSON = (url, options) => {
  return ajax(url, { ...options, method: "GET", responseType: "json" });
};

const post = (url, options) => {
  return ajax(url, { ...options, method: "POST" });
};

export { ajax, get, getJSON, post };
复制代码

发送请求:

<script>
      import { ajax, get, getJSON, post } from "./ajax/index.js";

      const url = "https://www.imooc.com/api/http/search/suggest?words=js";
   

      const p = getJSON(url, {
        params: { username: "alex" },
        data: { age: 18 },
        // timeoutTime: 10,
      }).then((res) => {
        console.log(res);
      });
      p.catch((err) => {
        console.log(err);
      });
</script>
复制代码

4.Ajax应用

Ajax应用-搜索提示

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>搜索提示</title>
  </head>
  <body>
    <input id="search" type="text" />
    <ul id="result"></ul>
    <script type="module">
      import { getJSON } from "./ajax/index.js";
      const url = "https://www.imooc.com/api/http/search/suggest?words=";

      const searchInput = document.getElementById("search");
      const resultList = document.getElementById("result");
      function handInputEvent() {
        if (searchInput.value.trim() !== "") {
          getJSON(`${url}${searchInput.value}`).then((res) => {
            console.log(res);

            let html = "";
            for (const item of res.data) {
              html += `<li>${item.word}<li>`;
            }
            resultList.innerHTML = html;
            resultList.style.display = "";

            res;
          });
        } else {
          resultList.innerHTML = "";
          resultList.style.display = "none";
        }
      }
      let timer = null;
      searchInput.addEventListener("input", () => {
        // handInputEvent(searchInput);

        if (timer) {
          clearTimeout(timer);
        }
        timer = setTimeout(handInputEvent, 2000);
      });
    </script>
  </body>
</html>

复制代码

Ajax应用-二级菜单

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>二级菜单</title>
    <style>
      /* css reset */
      * {
        padding: 0;
        margin: 0;
      }
      li {
        list-style: none;
      }

      /* menu */
      .menu {
        width: 100px;
        background-color: rgba(0, 0, 0, 0.1);
        margin: 10px;
      }
      .menu-item {
        position: relative;
        padding: 5px;
        cursor: pointer;
      }
      .menu-content {
        display: none;
        position: absolute;
        left: 100%;
        top: 0;
        width: 200px;
        height: 100px;
        padding: 0 5px;
        background-color: rgba(0, 0, 0, 0.1);
      }
      .menu-item:hover {
        background-color: rgba(0, 0, 0, 0.4);
      }
      .menu-item:hover .menu-content {
        display: block;
      }
      .menu-loading {
        margin: 45px 0 0 92px;
      }
    </style>
  </head>
  <body>
    <ul id="menu" class="menu">
      <!-- <li class="menu-item" data-key="hot" data-done="done">
        <span>热门</span>
        <div class="menu-content">
          <p><img class="menu-loading" src="./loading.gif" alt="加载中" /></p>
        </div>
      </li> -->
    </ul>

    <script type="module">
      // https://www.imooc.com/api/mall-PC/index/menu/hot
      // https://www.imooc.com/api/mall-PC/index/menu

      import { getJSON } from './ajax/index.js';
      const menuURL = 'https://www.imooc.com/api/mall-PC/index/menu';
      const menuEl = document.getElementById('menu');

      getJSON(menuURL)
        .then(repsonse => {
          // console.log(repsonse);

          let html = '';

          for (const item of repsonse.data) {
            html += `
              <li class="menu-item" data-key="${item.key}">
                <span>${item.title}</span>
                <div class="menu-content">
                  <p><img class="menu-loading" src="./loading.gif" alt="加载中" /></p>
                </div>
              </li>
            `;
          }

          menuEl.innerHTML = html;

          // [{key: "hot", title: "热门出发地", subTitles: Array(5)}]

          // ...
        })
        .then(() => {
          const items = menuEl.querySelectorAll('.menu-item');

          for (const item of items) {
            item.addEventListener(
              'mouseenter',
              () => {
                // console.log(item.getAttribute('data-key'));

                // IE11 开始支持
                // console.log(item.dataset.key);
                //防止重复发送,已经发送了的就不发送了
                if (item.dataset.done === 'done') return;

                getJSON(
                  `https://www.imooc.com/api/mall-PC/index/menu/${item.dataset.key}`
                )
                  .then(repsonse => {
                    // console.log(repsonse);

                    // [{title: "内地热门城市", cities: Array(27)}]

                    item.dataset.done = 'done';

                    let html = '';

                    for (const item of repsonse.data) {
                      html += `<p>${item.title}</p>`;
                    }

                    item.querySelector('.menu-content').innerHTML = html;
                  })
                  .catch(err => {
                    console.log(err);
                  });
              },
              false
            );
          }
        })
        .catch(err => {
          console.log(err);
        });
    </script>
  </body>
</html>

复制代码

Ajax应用-多个ajax请求的并发执行

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>多个 Ajax 请求的并发执行</title>
    <style>
      /* css reset */
      * {
        padding: 0;
        margin: 0;
      }
      li {
        list-style: none;
      }

      /* menu */
      .menu {
        width: 100px;
        background-color: rgba(0, 0, 0, 0.1);
        margin: 10px;
      }
      .menu-item {
        position: relative;
        padding: 5px;
        cursor: pointer;
      }
      .menu-content {
        display: none;
        position: absolute;
        left: 100%;
        top: 0;
        width: 200px;
        height: 100px;
        padding: 0 5px;
        background-color: rgba(0, 0, 0, 0.1);
      }
      .menu-item:hover {
        background-color: rgba(0, 0, 0, 0.4);
      }
      .menu-item:hover .menu-content {
        display: block;
      }
      .menu-loading {
        margin: 45px 0 0 92px;
      }

      /* loading-page */
      .loading-page {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        z-index: 1000;
        background-color: #eee;
        text-align: center;
      }
      .loading-img {
        position: absolute;
        top: 50%;
      }
      .ad img {
        display: inline-block;
        width: 25%;
      }
      .none {
        display: none;
      }
    </style>
  </head>
  <body>
    <div id="loading-page" class="loading-page">
      <img class="loading-img" src="./loading.gif" alt="加载中" />
    </div>

    <div id="ad" class="ad"></div>

    <ul id="menu" class="menu">
      <!-- <li class="menu-item" data-key="hot" data-done="done">
        <span>热门</span>
        <div class="menu-content">
          <p><img class="menu-loading" src="./loading.gif" alt="加载中" /></p>
        </div>
      </li> -->
    </ul>
    <script type="module">
      import { getJSON } from './ajax/index.js';

      const menuURL = 'https://www.imooc.com/api/mall-PC/index/menu';
      const adURL = 'https://www.imooc.com/api/mall-PC/index/ad';

      const loadingPageEl = document.getElementById('loading-page');
      const adEl = document.getElementById('ad');
      const menuEl = document.getElementById('menu');

      const p1 = getJSON(menuURL)
        .then(repsonse => {
          // console.log(repsonse);

          let html = '';

          for (const item of repsonse.data) {
            html += `
              <li class="menu-item" data-key="${item.key}">
                <span>${item.title}</span>
                <div class="menu-content">
                  <p><img class="menu-loading" src="./loading.gif" alt="加载中" /></p>
                </div>
              </li>
            `;
          }

          menuEl.innerHTML = html;

          // [{key: "hot", title: "热门出发地", subTitles: Array(5)}]

          // ...
        })
        .then(() => {
          const items = menuEl.querySelectorAll('.menu-item');

          for (const item of items) {
            item.addEventListener(
              'mouseenter',
              () => {
                // console.log(item.getAttribute('data-key'));

                // IE11 开始支持
                // console.log(item.dataset.key);

                if (item.dataset.done === 'done') return;

                getJSON(
                  `https://www.imooc.com/api/mall-PC/index/menu/${item.dataset.key}`
                )
                  .then(repsonse => {
                    // console.log(repsonse);

                    // [{title: "内地热门城市", cities: Array(27)}]

                    item.dataset.done = 'done';

                    let html = '';

                    for (const item of repsonse.data) {
                      html += `<p>${item.title}</p>`;
                    }

                    item.querySelector('.menu-content').innerHTML = html;
                  })
                  .catch(err => {
                    console.log(err);
                  });
              },
              false
            );
          }
        })
        .catch(err => {
          console.log(err);
        });

      const p2 = getJSON(adURL)
        .then(response => {
          // console.log(response);
          // [{ url: 'http://alimc.img.imooc.com/class/' }];

          let html = '';
          for (const item of response.data) {
            html += `<img src="${item.url}" alt="" />`;
          }
          adEl.innerHTML = html;
        })
        .catch(err => {
          console.log(err);
        });

      Promise.all([p1, p2]).then(() => {
        // loadingPageEl.style.display = 'none';

        // IE10 开始支持
        loadingPageEl.classList.add('none');
        // loadingPageEl.classList.remove('none');
      });
    </script>
  </body>
</html>
复制代码

第七部分 axios

axios官网:传送门

1.什么是axios?

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

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

复制代码

2. axios使用步骤

第一步:引入
// npm install axios

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
const url = "https://www.imooc.com/api/http/search/suggest?words=js";
//1.使用axios()方法
    axios(url, {
      //请求方式
      method: "post",
      // 请求头信息
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        // "Content-Type": "application/json",
      },
      // 通过请求头携带的数据
      params: {
        username: "alex",
      },
      // 通过请求体携带的数据
      //如果传的是这种对象,就会以json格式传过去,Content-Type就需要设置为指定的json格式
      // data: {
      //   age: 19,
      //   sex: "male",
      // },
      data: "age=18&sex=male",
    })
      .then((response) => {
        console.log(response);
        console.log(response.data.data);
      })
      .catch((err) => {
        console.log(err);
      });
//2.使用axios.get()方法:
    axios
      .get(url, {
        params: { username: "alex" },
      })
      .then((response) => {
        console.log(response);
      });
    //不需要设置content-type,而是根据你传的参数的格式自动设置
 //3.axios.post()方法:
    axios.post(url, { username: "alex" }).then((response) => {
      console.log(response);
    });
复制代码

3. axios()的一些属性

 <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script>
      axios({
        url: "https://www.imooc.com/api/http/search/suggest?words=js",
        baseURL: "",
        method: "post", // default
        // `headers` 是即将被发送的自定义请求头
        //给服务器说明我的格式,服务器拿到之后就会针对这种格式做不同处理
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        // headers: { "Content-Type": "application/json" },
        // `params` 是即将与请求一起发送的 URL 参数,必须是一个无格式对象(plain object)或 URLSearchParams 对象
        //写到这这里面的会自动编译成'?'  "&"传参的格式给请求地址
        params: {
          ID: 12345,
          name: "蔡徐坤",
        },
        /*
         data: POST是作为请求主体被发送的数据(默认是按照json格式发送的,需要先处理成字符串形式才能和header保持一致)

        */
        data: {
          firstName: "Fred111",
        },
        transformRequest:function(data){
            return Qs.stringify(data)
        },
        // timeout 指定请求超时的毫秒数(0 表示无超时时间),请求将被中断
        timeout: 0,

        // withCredentials表示跨域请求时是否需要使用凭证
        withCredentials: false, // default

        // responseType表示把服务器返回数据类型的格式转化为我们预设的格式,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
        responseType: "json", // default
      }).then((response) => {
        console.log(response);
      });
    </script>
复制代码

4.axios()的公供属性剥离出来

  <!-- 第一步:引入 -->
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script>
      // 第二步:配置默认信息
      axios.defaults.baseURL = "https://www.imooc.com";
      axios.defaults.headers["Content-Type"] =
        "application/x-www-form-urlencoded";

      // 添加请求拦截器
      axios.interceptors.request.use(
        function (config) {
          // 在发送请求之前做些什么
          return config;
        },
        function (error) {
          // 对请求错误做些什么
          return Promise.reject(error);
        }
      );

      /*
        添加响应拦截器
          拦截器:在请求或响应被 then 或 catch 处理前拦截它们设置响应拦截器:
          [成功状态]把从服务器获取的结果中的响应主体信息获取到即可,[失败状态]手动把错误信息抛出异常
     */
      axios.interceptors.response.use(
        function (response) {
          // 从服务器获取了数据
          return response.data;
        },
        function (error) {
          // 从服务器没有获取数据
          return Promise.reject(error);
        }
      );

      //第三步:发送自己单独的请求
      axios
        .get("/api/http/search/suggest?words=js", {
          params: {
            name: "xxxx",
            age: 19,
          },
        })
        .then((response) => {
          console.log(response);
        });

      axios
        .post(
          "/api/http/search/suggest?words=js",
          {
            name: "cccccc",
            age: 123213,
          },
          {}
        )
        .then((s) => {
          console.log(s);
        });
    </script>
复制代码

第八部分 fetch

fetch最新传送门

  • Fetch 也是前后端通信的一种方式
  • Fetch 是 XMLHttpRequest对象的一种替代方案,它是基于 Promise 的,浏览器原生提供这个对象

1.fetch()与XMLHttpRequest的区别:

    1. 调用fetch(url)直接返回了 Promise对象。
    1. fetch()采用模块化设计,API 分散在多个对象上(Response 对象、Request 对象、Headers 对象),更合理一些;相比之下,XMLHttpRequest 的 API 设计并不是很好,输入、输出、状态都在同一个接口管理,容易写出非常混乱的代码
    1. fetch()通过数据流(Stream 对象)处理数据,可以分块读取,有利于提高网站性能表现,减少内存占用,对于请求大文件或者网速慢的场景相当有用。XMLHTTPRequest 对象不支持数据流,所有的数据必须放在缓存里,不支持分块读取,必须等待全部拿到后,再一次性吐出来。

2.fetch 的基本用法

  • 1.fetch()可以只接受接受一个 URL 字符串作为参数,默认向该网址发出 GET 请求,返回一个 Promise 对象
      const url = "https://www.imooc.com/api/http/search/suggest?words=";

      fetch(url)
        .then(function (response) {
          // console.log(response);只能读取一次
          //请求是否成功
          if (response.ok) {
            return response.json();
          } else {
            throw new Error(`状态码异常${response.status}`);
          }
        })
        .then(function (responseData) {
          console.log(responseData.data);
        })
        .catch((err) => {
          console.log(err);
        });
复制代码

用await改写:

async function getJSON() {
  let url = 'https://api.github.com/users/ruanyf';
  try {
    let response = await fetch(url);
    return await response.json();
  } catch (error) {
    console.log('Request Failed', error);
  }
}
复制代码

3.fetch()的第二个参数:定制 HTTP 请求

3.1发送POST请求和json数据

const user =  { name:  'John', surname:  'Smith'  };
const response = await fetch('/article/fetch/post/user', {
  method: 'POST',
  headers: {
   'Content-Type': 'application/json;charset=utf-8'
  }, 
  body: JSON.stringify(user) 
});
复制代码

3.2发送POST请求和键值数据

const response = await fetch(url, {
  method: 'POST',
  headers: {
    "Content-type": "application/x-www-form-urlencoded; charset=UTF-8",
  },
  body: 'foo=bar&lorem=ipsum',
});
复制代码

3.3 post提交表单

const form = document.querySelector('form');

const response = await fetch('/users', {
  method: 'POST',
  body: new FormData(form)
})
复制代码

3.4 post上传文件

const input = document.querySelector('input[type="file"]');

const data = new FormData();
data.append('file', input.files[0]);
data.append('user', 'foo');

fetch('/avatars', {
  method: 'POST',
  body: data
});
复制代码

4.Response 对象:处理 HTTP 回应

  • fetch()发出请求以后,只有网络错误,或者无法连接时,fetch()才会报错,其他情况都不会报错,而是认为请求成功。
  • 只有fetch()发出请求通过Response.status属性,得到 HTTP 回应的真实状态码,才能判断请求是否成功.
  • 第一种判断方法:response.status属性只有等于 2xx (200~299),才能认定请求成功。这里不用考虑网址跳转(状态码为 3xx),因为fetch()会将跳转的状态码自动转为 200。
  • 另一种方法是判断response.ok是否为true。Response.ok属性返回一个布尔值,表示请求是否成功,true对应 HTTP 请求的状态码 200 到 299,false对应其他的状态码。
async function fetchText() {
  let response = await fetch('/readme.txt');
  if (response.status >= 200 && response.status < 300) {
    return await response.text();
  } else {
    throw new Error(response.statusText);
  }
}
//或者
if (response.ok) {
  // 请求成功
} else {
  // 请求失败
}
复制代码
  • response.headers.get(),用于读取某个标头的值。
let response =  await  fetch(url);  
response.headers.get('Content-Type')
// application/json; charset=utf-8
复制代码
  • 读取文本内容:
  • response.text():得到文本字符串。
  • response.json():得到 JSON 对象。
分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改