网络相关

Event Loop

js是单线程的,所有任务都在主线程上执行,形成一个执行栈,主线程外还存在一个任务队列,Event Loop是解决异步回调的一种机制,遇到同步任务时,直接压入执行栈执行,遇到异步任务,宏任务和微任务时会放入相应的队列中,当同步任务执行完毕,eventloop检查到了就会按顺序压入执行栈执行,执行完后开始渲染,然后不断重复。

浏览器输入URL后发生的事情

  1. URL检查 :先进行url的合法检查
    1. 合法 -> 检查完整度,不完整浏览器可能会对地址进行猜测,然后补齐前缀或后缀;
    2. 不合法 -> 将内容作为搜索条件,使用默认搜索引擎进行搜索。
  2. DNS解析域名 :操作系统会先检查浏览器缓存本地的hosts中是否有该网站的记录
    • 有 -> 直接从记录里找对应IP地址完成域名解析
    • 没有 -> 使用TCP/IP参数中设置的DNS服务器进行查询
      • 如果查询的域名包含在本地配置区域则直接返回解析结果,完成域名解析。
      • 没有的话检查本地DNS服务器是否缓存有该网站的记录,有的话返回解析结果,完成域名解析。
        • 还没有的话本地DNS 服务器会发送查询报文到根DNS服务器根DNS 服务器收到请求后返回顶级域DNS服务器地址,本地DNS 服务器再发查询报文到顶级域DNS服务器顶级域DNS服务器收到请求后,返回权威DNS 服务器的地址,本地DNS服务器再发送查询报文到权威DNS服务器权威DNS服务器收到后返回最终的IP地址,完成域名解析。
  3. 建立TCP连接 :当浏览器获取到服务器的IP地址后,浏览器会用一个随机的端口号向服务器80端口发送一个TCP连接请求,这个请求到达服务器后,会通过TCP三次握手建立TCP连接。
  4. 发送HTTP请求 :建立连接后就可以通过HTTP进行数据的传输,使用时HTPS会在TCP与HTTP直接多一层协议作为加密及认证的服务。HTTPS使用SSL和TLS协议,保障了信息的安全,SSL 协议的作用是认证客户端和服务器,确保数据发送到正确的客户端和服务器,加密数据,防止数据中途被窃取,维护数据的完整性,确保数据在传输过程中不会被改变。TLS协议的作用是用于在两个通信应用程序之间,提供保密性和数据完整性。TLS协议由TLS记录协议和TLS 握手协议组成。
  5. 服务器响应请求 :当浏览器和服务器建立连接之后,浏览器会发送一个初始的HTTP GET请求,请求目标通常是一个HTML文件,服务器收到请求后发回一个HTTP响应报文,内容包括相关的响应头和HTML正文。
  6. 渲染服务器:不同浏览器的渲染过程不太一样,谷歌是先处理HTML标记并构建DOM树,再处理CSS标记并构建CSS规则树,再将DOM树和CSS规则树合并构建一个Rander渲染树,根据渲染树来布局,以计算每个节点的几何信息,再绘制页面
  7. TCP断开连接:现在的浏览器页面为了优化请求的耗时都会默认开启持久连接,就是页面关闭TCP连接才会关闭,这个关闭的过程就是四次挥手。

TCP 的三次握手和四次挥手

TCP协议是传输层的一个面向连接的安全可靠的传输协议。

三次握手

三次握手的机制是为了保证能建立一个安全可靠的连接。

  • 第一次握手:由客户端发起,客户端会发送一个请求报文(报文中SYN = 1)。
  • 第二次握手:服务端收到这个报文后就知道客户端要发起一个新的连接,服务端就会发送一个确认消息的报文(ACK = 1),表示确认客户端发起的连接请求。
  • 第三次握手:两次握手后客户端已经知道自己发送的请求可以到达服务端,且服务端发送的响应也可以到达客户端,但此时服务端并不知道自己的响应报文是否能送达客户端,所以客户端需要发送第三次握手(ACK = 1),给服务端一个回应 三次握手后两方就都能确定消息能送到也能收到,实现双工,这样就可以建立起一个安全的连接。

四次挥手

  • 第一次挥手:客户端会发送一个请求报文(FIN = 1),服务器收到后就知道客户端要断开连接了。
  • 第二次挥手:此时服务端不一定传完数据了,所以只能进行一个消息的确认而不是同意。
  • 第三次挥手:此时服务端已经准备好断开连接了,所以会发送一个响应报文(FIN = 1)通知客户端我已经做好准备了
  • 第四次挥手:此时服务端依然不知道报文是否送达客户端,所以客户端要发起一个消息确认的报文。 经过四次挥手能确认客户端和服务端都准备好断开连接了,这样就能安全的断开一个连接。

HTTP && HTTPS加密

以前都是用HTTP协议的,但是HTTP协议传输的数据是公开的,很容易被劫取导致数据泄露,非常不安全。

所以有了HTTPS协议,现在基本上用的都是HTTPS,它对请求报文和响应报文都做了加密,即使被劫取了也得不到具体的数据。

HTTPS加密的方式

  1. 对称加密
    • 特点
      • 加密和解密使用相同的密钥
      • 很高效,适合大量数据的加密场景。
      • 算法公开,安全性取决于密钥大小,密钥越大效率越低。
    • 缺点
      • 算法本身安全,但使用的环境不安全,因为加密解密用的都是同一个密钥。
  2. 非对称加密
    • 特点
      • 使用匹配的一对密钥 来分别进行加密和解密,这两个密钥是公开密钥私有密钥
      • 公钥加密的数据只能用对于的私钥解开,同理私钥加密的也只能公钥解开。
      • 安全性高。
    • 缺点
      • 加密解密复杂、效率低、耗时长

过程

初期

一开始是使用对称加密。 浏览器向服务器发送请求的时候,需要把密钥也一起发送给服务器,传输过程中如果有黑客的话,可以直接截取请求和密钥进行解密,非常不安全!

中期

所以出现了非对称加密。 用的公钥和私钥,但是发送请求的时候需要把公钥也一同发送过去,这又跟对称加密一样,遇到了同样的坑,黑客可以截取公钥,形成自己的黑客公钥传给浏览器,伪造成服务器发的,然后浏览器使用公钥对自己的数据进行加密然后传输,黑客就用自己的私钥进行解密,然后再用服务器给的公钥进行加密伪造成浏览器发的。

后期

最后出现了认证机构

让浏览器有能力判断是否是服务器发送的公钥 。服务器将自己的公钥和域名发送给认证机构,认证机构也生成一个自己的公钥和密钥,用秘钥对服务器的公钥和域名进行加密生成服务器的证书 然后还给服务器,再将自己认证机构的公钥发给浏览器(用于解开服务器的证书)这样当浏览器需要向服务器发送请求时,可以先发送一个请求获取服务器证书 ,服务器将证书发过去,浏览器用认证机构的公钥进行解密,然后就能拿到服务器的公钥和域名了,然后下一步就是要发送请求报文了,但是如果用非对称加密再形成一个公钥和密钥,若有大量的数据会非常耗性能,这样就适得其反了。所以可以使用对称加密,将这里对称加密的密钥就称为会话密钥,但是不能直接会话密钥传输过去,不然还是可能被黑客拦截,这样前面的努力就都白费了。可以通过服务器的公钥将会话密钥加密 ,形成密文,传给服务器,然后服务器用私钥解密拿到会话密钥。这样浏览器就可以用会话密钥对请求报文进行加密安全传输过去,服务器也可以用会话密钥对响应报文进行加密,形成密文,安全传回去。

TCP和UDP

  • TCP可以保证连接的稳定可靠性 ,他发送的时候会带一些状态标记和序列号,能确认双方都可以接收和发送消息 ,且能够处理丢包、保证数据包按序到达
  • UDP是无连接 的,也没有序列号,无法保证双方能正常获取数据,也不会对数据进行确认,就是效率比TCP高

HTTP协议

超文本传输协议 ,规定了浏览器和万维网服务器之间相互通信的规则

规定了请求报文和响应报文。

HTTP请求交互的基本过程

浏览器 -> 服务器 :1. 请求行 2. 请求头 3. 请求体

服务器 -> 浏览器: 1. 状态行 2. 响应头 3. 响应内容

请求报文

js 复制代码
请求行   //1.请求类型   2.URL路径  3.HTTP协议版本
请求头       
          1.Host:
		2.Connection:
		3.Content-Type:
		4.Content-Length:
                ...
空行

请求体    // 用户信息和资源信息等
        //GET请求时请求体为空,POST请求时可以不为空
常用请求类型
js 复制代码
GET  //从服务器端读取数据
POST  //向服务器添加新数据
PUT  //更新服务端已有数据
DELETE  //删除服务端数据
POST 请求参数格式
js 复制代码
//1.  用于键值对参数,参数的键值用=连接,参数之间用&连接
Content-Type = application/x-www-form-urlencoded;charset-utf-8
 name=cloud&age=21
 
 
 //2. 用于JSON字符串
 Content-Type: application/json;charset=utf-8
 {
     "name" : "cloud",
     "age": 18
 }
 
 //3. 用于文件上传
 Content-Type: multipart/form-data

响应报文

js 复制代码
状态行   // 1.HTTP协议版本 2.状态码 3.状态码的原因语句(OK)
响应头部    
		1.Data
		2.Content-Type:请求体的类型 
		3.Content-Length:
				
空行
体  //  服务端返回的资源信息(一般是html形式的)
常见状态码
js 复制代码
200 --- OK 请求成功
201 --- Created 已创建,成功请求并创建新资源
401 --- Unauthorized 未授权,请求要求用户的身份认证
404 --- Not Found 服务器无法根据客户端的请求找到资源
500 --- Internal Server Error 服务器内部错误,无法完成请求

AJAX

Ajax是一种异步请求数据的web开发技术,是一个概念模型,是一种思想。它包含了多种技术,并不特指一种。

优点

  1. 可以在浏览器不刷新网页的情况下向服务器请求数据。
  2. 允许用户根据触发事件来更新部分页面内容

缺点

  1. 没有浏览历史,无法回退。
  2. 存在跨域问题(必须同源)。
  3. SEO不友好。
  • 同源策略:协议、域名、端口号必须一样
bash 复制代码
http://cloud.com:8000
http协议  cloud.com 域名 8000端口号

违背同源策略就是跨域

区别一般HTTP请求和AJAX请求

  • AJAX是一种特别的HTTP请求

  • 对于服务器来说没有任何区别,区别在于浏览器端。

  • 只有XHR或Fetch发出的才是AJAX请求,其他都是非AJAX请求。

  • 浏览器收到响应

    • 一般请求:浏览器一般会直接显示响应体数据,也就是刷新/跳转页面
    • AJAX请求:浏览器不对页面进行任何更新操作(不刷新),必须主动调用监视的回调函数并传入响应相关的数据。

XHR概念

使用XMLHttpRequest(XHR) 对象可以与服务器交互,也就是发送AJAX请求(实现AJAX思想),使得前端可以在不刷新页面的情况下获取数据,不影响用户的操作。

API

js 复制代码
XMLHttpRequest(): 创建XHR对象的构造函数
status:响应状态码值,比如200 404
statusText:响应状态文本
readyState:标识请求状态的只读属性
  0:初始
  1:open()之后
  2:send()之后
  3:请求中
  4:请求完成
open():初始化一个请求,参数('method', 'url' )
send(data):发送请求
abort():中断请求
onredaystatechange:绑定readyState改变的监听函数
responseType:指定响应数据的类型,如果`responseType='json'`,得到响应后的数据自动解析为JS
response:响应体数据,类型取决于responseType的指定
timeout:指定请求超时的时间,默认0代表没有限制
ontimeout:绑定请求超时的监听函数
getResponseHeader(name):获取指定名称的响应头值
getAllResponseHeaders():获取所有响应头组成的字符串
setRequestHeader(name, value):设置请求头

XHR发送AJAX请求

创建一个服务器

可以使用express创建一个服务器端。express是基于 Node.js 平台,快速、开放、极简的 Web 开发框架。 nodemon是一个可以实时监听服务器端变化的插件,这样服务器端就不用改一次必须重启一次才生效。

bash 复制代码
npm i express -g 
npm i nodemon -g
js 复制代码
//服务器端 server.js
const express = require('express');

//创建应用对象
const app = express();

//监听端口启动服务
app.listen(8000, () => {
    console.log('服务器已开启...');
});
//使用nodemon server.js开开启并监听服务器

路由规则

js 复制代码
//响应请求的路由规则
// app.xxx('响应url',(请求报文, 响应报文) => {})创建路由规则
//request 请求报文
//response 响应报文

app.get('/server', (request, response) => {
    //设置响应头
    //设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    //设置响应体
    response.send('Hello GET');
})

app.post('/server', (request, response) => {
    response.setHeader('Access-Control-Allow-Origin', '*');
    //设置允许自定义请求头
    response.setHeader('Access-Control-Allow-Headers', '*');
    response.send('Hello POST');
})

请求

js 复制代码
function GET() {
//创建一个XHR对象
	const xhr = XMLHttpRequest();
        //初始化请求
	xhr.open('GET', 'http://localhost:8000/server');
        //发送请求
	xhr.send();
        //监听请求的状态
	xhr.onreadystatechange = function () {
        //当readystate为4时表示请求送达
		if (xhr.readyState === 4) {
                //当状态码[200, 300)表示请求成功(可以获得之前响应)
			if (xhr.status >= 200 && xhr.status < 300) {
				console.log(xhr.response);
			}
		}
	}
}
function POST() {
    const xhr = XMLHttpRequest();
    xhr.open('POST','http://localhost:8000/server');
    //设置请求体的类型
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');
    //自定义请求头,在服务器端需要设置允许自定义
    xhr.setRequestHeader('Name', 'cloud');
    //POST可以发送请求体
    //格式比较灵活,与服务器要对应
    // xhr.send('a=100&b=200');
    xhr.send('a:100&b:200');
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status < 300) {
                console.log(xhr.response);
            }
        }
    }
}

GET && POST

  • 传输方式: GET是拼接在URL上传输的,POST是放在请求体里传输
  • 安全性:GET请求的数据是通过URL传输的,这意味着所有的请求数据都会在浏览器的历史记录、服务器的日志、网络设备的日志中留下记录,这在某些情况下可能会泄露敏感信息。POST的安全性比GET高
  • 历史记录&&缓存:GET是在URL上传播的,所以可以被缓存在历史记录中,还可以添加书签,而POST没有缓存记录所以不行
  • 幂等性:幂等性是指无论一个操作进行一次或多次,结果都是相同的。GET是幂等的,POST不是,GET发送多次请求的请求结果都是相同的,而POST是创建一个数据,所以多次请求会创建多个相同数据
  • 大小限制:因为GET是在URL上传输的,所以有大小限制,URL的长度限制为2000字符左右,所以发大量数据的时候用POST更好
  • 数据类型:GET请求的数据类型通常是字符串,而POST是多样性的,例如JSON、XML、图片等资源

当响应数据为json时

json对象包含两个方法

  • json.parse()是将JSON格式的字符串转换为 JS的对象或者数组
  • json.stringify()是将JS的对象或数组转换为JSON
js 复制代码
//响应
app.all('/json-server', (req, res) => {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Header'.'*');
    
    const data = {
        name: 'cloud'
    }
    //对响应对象转换为json格式
    let str = JSON.stringify(data);
    
    response.send(str);
    
})
//请求
function JSON() {
    const xhr = new XMLHttpRequest();
    
    //设置响应体的数据类型(可以自动转化json数据)
    xhr.responseType = 'json';
    
    xhr.open('GET', 'http://localhost:8000/json-server');
    xhr.send();
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status < 300) {
                 console.log(xhr.response);
            }
        }
    } 
}

网络超时/异常

js 复制代码
//设置定时器模拟网络超时
app.get('/delay', (req, res) => {
    res.setHeader('Access-Control-Allow-Origin', '*');
    setTimeout(() => {
        response.send('Hello  delay');
    }, 3000)
})

//请求
function delay() {
    const xhr = new XMLHttpRequest();
    
    //超时设置  在规定时间内未响应就取消请求(自动)
    xhr.timeout = 2000;
    
    //网络异常的回调
    xhr.onerror = funtcion() {
         alert('哎哟( ̄y▽, ̄)╭  你的网咋这么不经用捏');
    }
    
    xhr.open('GET', 'http://localhost:8000/delay');
    xhr.send();
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status < 300) {
                console.log(xhr.response);
            }
        }
    }
    
}

手动取消请求

js 复制代码
app.get('/cancel', (req, res) => {
    res.setHeader('Access-Control-Allow-Origin', '*');
    setTimeout(() => {
        response.send('Hello  Cancel');
    }, 3000)
})

//请求
//xhr不止在一个函数里使用,所以得定义成全局
let xhr = null;
function send() {
    xhr = new XMLHttpRequest();
    xhr.open('GET','http://localhost:8000/cancel');
    xhr.send();
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4){
            if (xhr.status >= 200 && xhr.status < 300){
                console.log(xhr.response);
            }
        }
    }
}
function cancel() {
    //手动取消请求
     xhr.abort();
}

重复请求

js 复制代码
app.get('/repeat', (request, response) => {
    response.setHeader('Access-Control-Allow-Origin', '*');
    setTimeout(() => { 
        response.send('Hello Repeat');
    }, 3000)
   
});

//请求
let xhr = null;
//设置一个标识变量
let isSending = false;// 是否正在发送中
function send() {
    //先判断是否有正在发送的请求,若有则取消
    if (isSending) xhr.abort();
    xhr = new XMLHttpRequest();
    //创建好一个请求就说明要发送,可以设置为true
    isSending = true;
    xhr.open('GET', 'http://localhost:8000/repeat');
    xhr.send();
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
            //当状态码为4就表明发送成功了
            //无论请求的得到的响应结果如何,只要为4,就表明服务器已经收到请求了,所以可以设为false
            isSending = false;
            
            if (xhr.status >= 200 && xhr.status < 300) {
                console.log(xhr.response);
            }
        }
    }
}

XHR封装AJAX(低配axios)

特点

  1. 函数的返回值为promise,成功的结果为response,异常结果为error
  2. 能处理多种类型的请求: GET/POST/PUT/DELETE
  3. 函数的参数为一个配置对象:
js 复制代码
{
	url: '', // 请求地址
	method:'', // 请求方式
	params: {}, // 请求的query参数
    data: {} // 请求的请求体参数
}
//参数传递的两种方式 params和data
//params是添加到url的请求字符串中的,用于GET请求。
//data是添加到请求体(body)中的, 用于POST请求。
  1. 响应json数据时自动解析为js

使用json-server扮演一个服务器

  1. 安装json-server npm i json-server -g
  2. 新建db.json并存入数据
json 复制代码
{
  "posts": [
    {
      "title": "majo",
      "autor": "goods",
      "id": 1
    },
    {
      "title": "甄嬛传",
      "autor": "cloud",
      "id": 5
    }
  ],
}
  1. 启动服务器json-server --watch db.json
  2. 接口规则-RESTful说明
接口地址 请求方式 适用情况
/posts GET 查询所有数据
/posts/id GET 查询单条数据
/posts POST 添加数据
/posts/id DELETE 删除数据
/posts/id PUT 修改数据

实现

  1. 定义一个axios函数,函数的参数为基础配置 function axios(config) {} ,我们将它写成一个对象。
js 复制代码
//url不给默认值,就是必须传,否则会报
//其余都给一个默认值
function axios ({
	url,
	method = 'GET',
	parmas = {},
	data = {}
}) {}
  1. 返回一个promise对象
js 复制代码
function axios({
    url,
	method = 'GET',
	parmas = {},
	data = {}
}) {
	return new Promise((resolve, reject) => {
        //对method大小写的处理
        //使用axios函数的时候,有可能会写post而不是POST
        method = method.toUpperCase();//转换成大写
        
       
        //params是拼接在url上的参数,所以需要对params进行处理
        //创建一个变量用来保存转换后params的字符串
        let queryString = '';
        //因为params传进来的是一个对象,所以需要对里面的属性进行遍历
        Object.keys(params).forEach(key => {
            queryString += `${key}=${params[key]}&`;
        })
        //拼接完后结尾会多一个&需要删除
        if (queryString) {
            //subString(开始位置,结束位置) 可以截取出开始到结束位置的字符串
            queryString = queryString.subString(0, queryString.length - 1) //截取出除了最后一位的所有内容
            //最后拼接在url上
            url += '?' + queryString;
        }
        
//执行异步ajax请求
	//1.创建xhr对象
        const xhr = new XMLHttpRequest();
	//2.初始化请求
        xhr.open(method, url);
	//3.发送请求
        //判断发送的方法
        if (method === 'GET' || method = 'DELETE')
            //GET是不能设置请求体的,所以直接发送
            xhr.send();
        else if (method === 'POST' || method === 'PUT') {
            //设置请求头--->设置请求体发送的数据的格式
            xhr.setRequestHeader('Content-Type', 'application/json;charsrt=utf-8');
            //将请求体内的对象转化为json格式的字符串后发送
            xhr.send(JSON.stringify(data));
        }
	//4.判断是否成功
        //绑定状态改变的监听事件
        xhr.onreadystatechange = function () {
             //解构函数 用readyState代替 xhr.readyState
            const {readyState, status, statusText} = xhr;
            //如果不是4直接return
            if (readyState !== 4)  return;
            //如果成功执行resolve()
            if (status >= 200 && status < 300) {
                //成功的话会返回响应体,需要准备一个对象存储
                const response = {
                    //响应的json对象转换为js
                    data: json.parse(xhr.response);
                    status,
                    statusText
                }
                resolve(response);
            }
		//如果失败执行reject()
            else {
                //返回一个error对象,并携带error.message
                reject(new Error('request error status is :' + status));
            }
        }
		
	})
}
  1. 使用封装的axios函数
js 复制代码
//这边设置了四个button,分别绑定了点击事件GET、POST、PUT、DELETE

 // GET请求 客户端获取数据
function GET() {
    axios({
        url: '请求的路径',
        method: 'GET',
        params: {
            id: 2,
            title: '甄嬛'
        }
    }).then(response => {
        console.log(response);
    },error => {
        alert(error.message);
    })
}

//POST请求 服务器保存数据
function POST() {
    axios({
        url: '请求的路径',
        method: 'POST',
        data: {
	      "title": "甄嬛",
           "autor": "cloud"
        }
    }).then(response => {
        console.log(response);
    },error => {
        alert(error.message);
    })
}

//PUT请求 更新数据
function PUT () {
	axios({
		url: '请求的路径',
         method: 'PUT',
         data: {
             "title": 'majo',
             "autor": "goods"
         }
      }).then(response => {
           console.log(response);
      },error => {
           alert(error.message);
      })
}

 //DELETE请求 更新数据
function PUT () {
	axios({
		url: '请求删除的路径',
         method: 'DELETE'
      }).then(response => {
           console.log(response);
      },error => {
           alert(error.message);
      })
}

axios

axios是一个基于promise、基于XHR进行二次封装的网络请求库。

特点

  1. 基于promise的异步ajax请求库
  2. 浏览器/node都可以使用。
  3. 支持请求/响应拦截器 (统一对请求、响应做处理的函数)。
  4. 支持请求取消
  5. 支持请求/响应数据转换
  6. 支持批量发送多个请求。

常用API

js 复制代码
axios(config) //可以设置任意类型请求的方式
axios(url[,config]) // 可以只指定url发get请求
axios.request(config) //等同于axios(config)
axios.get(url[,config]) //发get请求
axios.post(url[,config]) //发post请求
axios.put(url[,config]) //发put请求
axios.delelte(url[,config]) //发delete请求

axios.defaults.xxx //请求的 默认全局配置
axios.interceptors.request.use() //添加请求拦截器
axios.interceptors.response.use() //添加响应拦截器

axios.create([config])  //创建一个欣的axios

axios.Cancel() //用于创建取消请求的  错误对象
axios.CancelToken() //用于创建取消请求的  token对象
axios.isCancel() //是否是一个取消请求的错误
axios.all(promises) //用于批量执行多个异步请求
axios.spread() //与all配合使用,用来指定接收所有成功数据的回调函数 的方法

axios.create([config])

根据指定配置创建一个新的axios,也就是每个新的axios都有自己的位置,实现重新配置自身属性 ,向多个不同的服务器请求/发送数据

  • 新axios没有取消和批量发送请求的方法,其余都一样

    为什么要设计这个语法?

    • 需求:项目中有部分接口需要配置与另一部分接口不一样的内容,如何处理?

    • 解决:创建2个新的axios,每个都有自己特有的配置,分别应用到不同需求的接口请求中。

js 复制代码
//axios全局的baseURL
axios.defaults.baseURL = 'http://localhost:3000';
axios.get('/posts');
//当有多个服务器需要请求时
//可以通过创建一个新的axios去配置一些不同于全局,
//但是不止一个请求会使用的配置
//实现复用
const instance = axios.create({
   //创建instance的baseURL
   baseURL: 'http://localhost:4000'
})

//使用instance发送请求
instance.get('/posts'); //会向http://localhost:4000/posts发送请求

axios.interceptors拦截器

当多个请求接口有相同的配置、和相同的响应处理时,可以统一在拦截器里写,这样会减少代码的耦合度。

js 复制代码
//创建一个请求
axios.get('http://localhost:3000/posts')
       .then(response => {
            console.log('response.data', response.data);
        },
            error => {
                console.log('error:', error.message);
 })
js 复制代码
//创建2个请求拦截器和响应拦截器

//添加请求拦截器(回调函数)
       axios.interceptors.request.use(
           //成功的回调
           config => {
               console.log('request interceptor1 onResolved()');
               return config
           },
           //失败的回调
           error => {
               console.log('request interceptor1 onRejected()');
               return Promise.reject(error);
           }
       );
       axios.interceptors.request.use(
           config => {
               console.log('request interceptor2 onResolved()');
               return config
           },
           error => {
               console.log('request interceptor2onRejected()');
               return Promise.reject(error);
           }
       );

       //添加响应拦截器
       axios.interceptors.response.use(
           response => {
               console.log('response interceptor1 onResolved()');
               return response
           },
           error => {
               console.log('response interceptor1 onRejected()');
               return Promise.reject(error);
           }
       );
       axios.interceptors.response.use(
           response => {
               console.log('response interceptor2 onResolved()');
               return response
           },
           error => {
               console.log('response interceptor2 onRejected()');
               return Promise.reject(error);
           }
       )
js 复制代码
//执行顺序


 //请求拦截器先进后出,响应拦截器按顺序执行,最后执行请求函数的回调
//源码时unshift压入所以先进后出
 request interceptor2 onResolved()
 request interceptor1 onResolved()
 response interceptor1 onResolved()
 response interceptor2 onResolved()
 response.data (4) [{...}, {...}, {...}, {...}]

axios取消请求

想要实现取消必须添加配置cancelTok

js 复制代码
//保存取消请求的函数
let cancel;
...
cancelToken: new axios.CancelToken((c) => {	//c是用于取消当前请求的函数
   //保存取消函数, 用于之后可能需要取消当前请求
   cancel = c;
})
...
//执行取消请求
cancel();

实现

js 复制代码
//保存取消请求的函数
let cancel;
function getProducts1 () {
    axios.get('请求路径',{
		cancelToken: new axios.CancelToken((c) => {
			cancel = c;
		})
	}).then(response => {
    	cancel = null;// 请求成功了后无法取消
    	console.log(response.data);
	},error => {
    	cancel = null;// 请求成已经失败了也无法取消
    	console.log('请求失败了',error.message);
	})
}

function cancelRequest(cancel) {
    //如果取消请求的函数存在则执行
    //因为如果没有发起请求,则cancel没有内容,点击取消按钮是无效的
    if (typeof cancel === 'function') {
        //执行取消请求的函数
        cancel('强制取消请求');
    }else {
        console.log('没有可取消的请求');
    }
}
// 点击请求,请求中再点击取消请求,会打印 '请求失败了 没有可取消的请求'
// 当取消请求后,axios请求会走error,error对象也会变成Cancel特殊对象
//如果没有取消请求而是报错,则error就是Error对象

取消一个重复请求

只要在发请求之前判断cancel是否为一个function即可,如果是一个function,则说明有请求正在发送。

js 复制代码
...
function getProducts1() {
            //在发请求之前检查cancel是否是一个function
            //如果是则说明有请求正在发送
            if (typeof cancel === 'function') {
                cancel('自动取消了上一个请求');
            }
            axios.get(...)...
...
问题

连续点击三次,只有第一次的会被取消 ,因为第二次点击,cancel=null,在请求中的情况下,再一次点击请求按钮的时候,cancel依旧是null,就不会执行 if (typeof cancel === 'function') { cancel('取消了上一个请求'); } 所以就无法取消第二次请求。

所以需要加判断,如果是手动取消的请求不需要cancel = null,这样每一次点击都可以通过if (typeof cancel === 'function') { cancel('取消了上一个请求'); } 去判断是否正在请求中。

js 复制代码
...
error => {
    if (axios.isCancel(error)) {
 		console.log('手动取消请求');
	}
	else {
    	cancel = null;
		console.log('请求出错!');
	}
}

耦合度

当不止一个请求,但素请求的某些配置又一样的时候,如果每请求一个接口都要这么写会很难看。 所以可以使用拦截器!!!

js 复制代码
//请求拦截器
axios.interceptors.request.use(config => {
     //在发请求之前检查cancel是否是一个function
    //取消未完成的请求
    if (typeof cancel === 'function') {
        cancel('自动取消了上一个请求')
    }
    //添加一个cancelToken配置
    config.cancelToken = new axios.CancelToken(c => {
        cancel = c;
    })
	return config
})

//响应拦截器
axios.interceptors.response.use(response => {
    cancel = null;
    return response;
},error => {
    if (axios.isCancel(error)) {
        console.log('自动取消了上一个请求');
         //在响应器里做出取消请求的处理结果,不需要请求里面的error做出处理
        //又因为是链式调用,所以得在这里return一个空的promise结束链式调用,不往下传递
        return new Promise(() => {})
    }
    else {
        //在这里做取消请求的标记
        cancel = null;
        //但是处理结果还是在请求的error里处理
        //因为每一个请求的接口的处理方式可能不同
        // 所以要传递一个promise下去链式调用处理
        return Promise.reject(error);
    }
})


//这样下面的代码就会非常清爽

function getProducts1() {
    axios.get('http://localhost:4000/products1').then(response => {
        console.log(response.data);
    	},
    	error => {
        	console.log('请求出错1!', error.message);
    	})
}

function getProducts2() {
    axios.get('http://localhost:4000/products2').then(response => {
        console.log(response.data);
   	 	},
        error => {
       	 	console.log('请求出错2!', error.message);
    })

}

function cancelRequest(cancel) {
    if (typeof cancel === 'function') {
        cancel();
    }
    else {
        console.log('抱歉哦亲,没有可取消的请求');
    }
}

Ajax Fetch Axios

网络请求 特点
Ajax 一种思想、技术统称,主要利用XHR实现网络请求。
Fetch 具体的一个API,基于promise,实现网络请求。
Axios 一个封装库,基于XHR二次封装,也使用了promise,较为推荐使用。
相关推荐
四喜花露水5 分钟前
Vue 自定义icon组件封装SVG图标
前端·javascript·vue.js
前端Hardy15 分钟前
HTML&CSS: 实现可爱的冰墩墩
前端·javascript·css·html·css3
web Rookie1 小时前
JS类型检测大全:从零基础到高级应用
开发语言·前端·javascript
Au_ust1 小时前
css:基础
前端·css
帅帅哥的兜兜1 小时前
css基础:底部固定,导航栏浮动在顶部
前端·css·css3
yi碗汤园1 小时前
【一文了解】C#基础-集合
开发语言·前端·unity·c#
就是个名称1 小时前
购物车-多元素组合动画css
前端·css
编程一生1 小时前
回调数据丢了?
运维·服务器·前端
丶21362 小时前
【鉴权】深入了解 Cookie:Web 开发中的客户端存储小数据
前端·安全·web
Missmiaomiao3 小时前
npm install慢
前端·npm·node.js