一、前后端交互与HTTP协议
前后端通信的过程
#mermaid-svg-BOXlEfVBj6SaQFZQ {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-BOXlEfVBj6SaQFZQ .error-icon{fill:#552222;}#mermaid-svg-BOXlEfVBj6SaQFZQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BOXlEfVBj6SaQFZQ .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-BOXlEfVBj6SaQFZQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BOXlEfVBj6SaQFZQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BOXlEfVBj6SaQFZQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BOXlEfVBj6SaQFZQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BOXlEfVBj6SaQFZQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BOXlEfVBj6SaQFZQ .marker.cross{stroke:#333333;}#mermaid-svg-BOXlEfVBj6SaQFZQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BOXlEfVBj6SaQFZQ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-BOXlEfVBj6SaQFZQ .cluster-label text{fill:#333;}#mermaid-svg-BOXlEfVBj6SaQFZQ .cluster-label span{color:#333;}#mermaid-svg-BOXlEfVBj6SaQFZQ .label text,#mermaid-svg-BOXlEfVBj6SaQFZQ span{fill:#333;color:#333;}#mermaid-svg-BOXlEfVBj6SaQFZQ .node rect,#mermaid-svg-BOXlEfVBj6SaQFZQ .node circle,#mermaid-svg-BOXlEfVBj6SaQFZQ .node ellipse,#mermaid-svg-BOXlEfVBj6SaQFZQ .node polygon,#mermaid-svg-BOXlEfVBj6SaQFZQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-BOXlEfVBj6SaQFZQ .node .label{text-align:center;}#mermaid-svg-BOXlEfVBj6SaQFZQ .node.clickable{cursor:pointer;}#mermaid-svg-BOXlEfVBj6SaQFZQ .arrowheadPath{fill:#333333;}#mermaid-svg-BOXlEfVBj6SaQFZQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-BOXlEfVBj6SaQFZQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-BOXlEfVBj6SaQFZQ .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-BOXlEfVBj6SaQFZQ .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-BOXlEfVBj6SaQFZQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-BOXlEfVBj6SaQFZQ .cluster text{fill:#333;}#mermaid-svg-BOXlEfVBj6SaQFZQ .cluster span{color:#333;}#mermaid-svg-BOXlEfVBj6SaQFZQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-BOXlEfVBj6SaQFZQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}
请求数据
响应数据
浏览器
服务器
同一个域名下可以同时有6个并发的请求
二、HTTP协议
1.HTTP是什么?
HyperText Transfer Protocol,超文本传输协议
超文本:原先一个个单一的文本,通过超链接将其联系起来。由原先的单一文本变成了可无限延伸、扩展的超级文本、立体文本
(HTML,css,js,图片,视频,音频等都是通过HTTP协议在服务器和浏览器之间传输)
注意:每一次的前后端通信,前端需要主动向后端发出请求,后端接收到前端的请求后,可以给出响应(HTTP是一个请求-响应协议)
2.HTTP报文
请求报文
浏览器向服务器发送请求时,请求本身就是信息,叫请求报文
响应报文
服务器向浏览器发送响应时传输的信息,叫响应报文
get请求没有请求体,数据通过请求头携带
post请求有请求体,数据通过请求体携带
3.HTTP方法
浏览器发送请求时采用的方法,和响应无关
用来定义对于资源采用什么样的操作,有各自的语义
GET // 获取数据(查)
POST // 创建数据(增)
PUT // 更新数据(改)
DELETE // 删除数据(删)
RESTful接口设计
一种接口设计风格,充分利用HTTP方法的语义
GET和POST方法对比
- 语义:> GET:获取数据> > POST:创建数据
- 发送数据> GET 通过地址在请求头中携带数据,能携带的数据量和地址的长度有关系,一般最多就几K> > POST 既可以通过地址在请求头中携带数据,也可以通过请求体携带数据,能携带的数据量理论上是无限的(携带少量数据,可以使用GET请求,大量的数据可以使用POST请求)
- 缓存> GET 可以被缓存> > POST不会被缓存
- 安全性> GET和POST都不安全
(发送密码或其他敏感信息时不要使用GET,主要是避免直接被他人窥屏或通过历史记录找到密码)
4. HTTP状态码
定义服务器对请求的处理结果
语义
状态码语义100 ~ 199消息:代表请求已被接受,需要继续处理200 ~ 299成功300 ~ 399重定向301Moved Permanently302Move Temporarily304Not Modified400 ~ 499请求错误404Not Found500 ~ 599服务器错误
三、本地存储
1. Cookie
Cookie 是浏览器存储数据的一种方式
因为存储在用户本地,而不是存储在服务器上,是本地存储
一般会自动随着浏览器每次请求发送到服务器端
Cookie的属性
- 名称和值> 创建Cookie时必须要填写,其他属性可以使用默认值> > 名称或值如果包含非英文字母,则写入时使用encodeURIComponent()编码,读取时使用decodeURIComponent()解码> >
> document.cookie =`${encodeURIComponent('用户名')} = ${encodeURIComponent('李四')}`;>
- 失效时间- 会话Cookie如果没有设置失效时间,它存在内存当中,当会话结束,Cookie消失想长时间存在,设置
Expires
或Max-Age``````document.cookie =`username = name; expires = ${newDate('2100-1-01 00:00:00')}`;document.cookie ='username = name; max-age = 5'// Expires值为Date类型// Max-Age 值为数字,表示当前时间之后多少秒过期(如果值为0或负数,则Cookie会被删除)
- Domain域> 限定了访问Cookie的范围(不同域名)> > 使用 js 只能读写当前域或父域的Cookie,无法读写其他域的Cookie
- Path路径> 限定了访问Cookie的范围(同一域名下)> > 当Name、Domain、Path这三个字段都相同的时候,才是同一个Cookie
- HttpOnly> 只要设置了这个属性,Cookie不能通过js访问(不能从前端设置,只能从后端设置该属性)
- Secure> 限定了只有在https而不是http的情况下才可以发送给服务端
注意
- 前后端都可以设置Cookie
- 每个域名下的Cookie数量有限当超过单过域名限制之后,再设置Cookie,浏览器就会清除以前设置的Cookie
- Cookie有大小限制每个Cookie的存储容量很小,最多只有4KB左右
封装Cookie
constset=(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;}constget=name=>{
name =`${encodeURIComponent(name)}`;const cookies = document.cookie.split('; ');for(const item of cookies){const[cookieName, cookieValue]= item.split('=');if(cookieName === name){returndecodeURIComponent(cookieValue);}}return;}constremove=(name,{domain, path})=>{set(name,'',{domain, path,maxAge:-1});};
2. localStorage
也是一种浏览器存储数据的方式,只是存储在本地,不会发送到服务器端
单个域名下的localStorage总大小有限制(一般最大5M左右)
方法
- setItem
- getItem
- removeItem
- clear
注意
- localStorage的存储期限> localStorage是持久化的本地存储,除非手动清除,否则数据是永远不会过期的
- localStorage键和值的类型> 存储的键和值只能是字符串类型> > 不是字符串类型,也会先转化成字符串类型再存进去
- 不同域名不能共用localStorage
- localStorage的兼容性> IE7及以下版本不支持,IE8开始支持
四、Ajax&Fetch 与跨域请求
1. Ajax
Asynchronous JavaScript and XML(异步JavaScript和XML)的简写
Ajax中的异步:可以异步地向服务器发送请求,在等待响应的过程中,不会阻塞当前页面,浏览器可以做自己的事情。直到成功获取响应后,浏览器才开始处理响应数据。
XML(可扩展标记语言),是前后端数据通信时传输数据的一种格式
Ajax就是浏览器与服务器之间一种异步通信的方式
可以在不重新加载整张页面的情况下,对页面的某部分进行更新
Ajax使用步骤
- 创建XHR对象
const xhr =newXMLHttpRequest();
- 准备发送请求
xhr.open('HTTP方法','地址URL', 是否异步);// 做好发送请求前的准备工作
- 发送请求
xhr.send();// 调用send正式发送请求(参数是通过请求体携带的数据)
- 监听事件,处理响应当获取到响应后,会触发xhr对象的readystatechange事件,可以在该事件中对响应进行处理(响应的内容会自动填充xhr对象的属性)> readystatechange 事件监听 readyState 这个状态的变化,它的值从 0 ~ 4,一共5个状态> > 0 : 未初始化。尚未调用open()> > 1 : 启动。已经调用open(),但尚未调用send()> > 2 : 发送。已经调用send(),但尚未接受到响应> > 3 : 接收。已经接收到部分响应数据> > 4 : 完成。已经接收到全部响应数据,而且已经可以在浏览器中使用了
xhr.onreadystatechange=()=>{if(xhr.status !==4)return;// status HTTP 状态码// statusText 状态说明if((xhr.status >=200&& xhr <300)|| xhr.status ===304){ console.log('正常使用');// responseText 数据作为文本存在}else{ console.log('处理错误');}}
注意:1. 为了兼容性,readystatechange中不适用this,直接使用xhr2. 为了兼容性,将第4步放在open之前const xhr =newXMLHttpRequest();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);}}xhr.open('GET', url,true);xhr.send('null');
2. JSON
JavaScript Object Notation
Ajax发送和接收数据的一种格式
JSON的三种形式
JSON 中不支持注释,不支持 undefined
- 简单值形式> 对应 JS 中的基础数据类型(不包含undefined)
- 对象形式> 对应 JS 中的对象
- 数组形式> 对应 JS 中的数组
JSON的常用方法
- JSON.parse()> 将 JSON 格式的字符串解析成 JS 中的对应值
- JSON.stringify()> 将 JS 的基本数据类型、对象或数组转换成 JSON 格式的字符串
3. 跨域
跨域请求会被浏览器阻止
协议、域名、端口号任何一个不一样,就是不同域
浏览器阻止跨域请求,是浏览器本身的一种安全策略(同源策略)
4. 跨域解决方案
CORS 跨域资源共享
过程
- 浏览器发送请求
- 后端在响应头中添加Access-Control-Allow-Origin头信息
- 浏览器接收到响应
- 如果是同域下的请求,浏览器不会额外做什么,这次前后端通信就完成了
- 如果是跨域请求,浏览器会从响应头中查找是否允许跨域访问
- 若允许,则通信完成
- 若没找到或不包含想要跨域的域名,就丢弃响应结果
JSONP
script 跨域不会被浏览器阻止,JSONP利用script标签加载跨域文件
5. XHR 对象
responseType可以用默认值
text
(在发送之前设置),这是用response或responseText都可以接收数据
但当responseType为
json
时,只能用response来接收(得到的是JSON格式的)
timeout属性
设置请求的超时时间(ms)
withCredentials属性
指定使用Ajax发送请求时是否携带Cookie
使用Ajax发送请求,默认情况下,同域时,会携带Cookie,跨域时不会
要想在跨域时携带数据,就设置该属性为true
最终能否成功跨域携带Cookie,还要看服务器同不同意(默认不同意)
abort() 方法
终止当前请求,在发送完请求之后调用
setRequestHeader()
设置请求头信息,
xhr.setRequestHeader(头部字段的名称, 头部字段的值);
一般用来设置请求头中的content-Type字段,用来告诉服务器,浏览器发送的数据是什么格式的
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');// 名值对格式
xhr.serRequestHeader('Content-Type','application/json');// json 格式
事件
- load事件(响应事件可用时触发)可以用来代替readystatechange事件
- error事件(请求发生错误时触发)
- abort事件(调用abort() 终止请求时触发)
- timeout事件(请求超时后触发)
5. axios 和 Fetch
axios 是一个基于 Promise 的HTTP库,可以用在浏览器和 node.js 中
axios(url,{method:'post',headers:{'Content-Type':'application/x-www-form-urlencoded'// 'Content-Type': 'application/json'},// 通过请求头携带数据params:{username:'zhangsan'},// 通过请求体携带数据// application/json// data: {// age: 18// }// application/x-www-form-urlencodeddata:'age=18&sex=male',timeout:1000,// 是否跨域携带 Cookie// withCredentials: true}).then(response=>{
console.log(response);}).catch(err=>{
console.log(err);});
axios.get(url,{params:{username:'lisi'}}).then(response=>{
console.log(response);}).catch(err=>{
console.log(err);});
axios.post(url,{username:'wangwu'}).then(response=>{
console.log(response);}).catch(err=>{
console.log(err);});
Fetch 是前后端通信的一种方式,是 Ajax 的一种替代方案,它是基于 Promise 的
const fd =newFormData();
fd.append('username','wangwu');// 传formdata数据不需要设置headersfetch(url,{// 第二个参数可以不传,用默认值method:'post',// 如果要通过url携带参数只能在url中手动加入body:'username=zhangsan&age=18',// 如果要传对象,只能用JSON.stringify()headers:{'Content-Type':'application/x-www-form-urlencoded'// application/json},mode:'cors',// 是否跨域,默认为corscredentials:'include'// 是否携带cookie}).then(response=>{if(response.ok){return response.json();// return response.text(); // 数据不是json个数时,用这个}else{thrownewError(`HTTP CODE 异常 ${response.status}`)}}).then(data=>{
console.log(data);}).catch(err=>{
console.log(err);});
6. async / await
使基于 Promise 的异步操作更简洁、方便
async/await 简化 Promise 的链式调用
使异步代码看起来像同步代码,更容易理解
async 函数的返回值
返回值就是Promise对象,如果返回的不是Promise对象,也会用Promise对象进行包装,如果是Promise对象,就直接返回
三种形式
asyncfunctionfun(){};constfun2=asyncfunction(){};constfun3=async()=>{};
注意:
- async函数默认情况下返回成功状态的Promise对象
- 要想返回失败状态
// 1return Promise.reject();// 2thrownewError();
可以通过try…catch或Promise的catch来捕获错误 - async函数中可以没有await
await 机制
async 函数中的代码有先后顺序,await 会阻塞该async函数中代码的执行(只有当 await 后面的异步代码执行完成,才可以继续往下执行)
async函数内部是同步执行的,它本身是异步的
await的值
- 如果 await 后面是 Promise 对象,它的值就是 Promise 对象的结果
- 如果不是Promise对象,那么会用Promise对其进行包装
注意:
- async 函数内部所有 await 后面的 Promise 对象都成功,async函数返回的Promise对象才会成功;只要任何一个 await 后面的 Promise对象失败,那么 async 函数返回的Promise 对象就会失败
- await 一般只能用在 async 函数中(有的浏览器也可以用在模块最顶层,借用 await 解决模块异步加载的问题)
使用async/await处理并发问题
处理异步操作时,如果不存在继发关系,最好让它们并发执行
- 可以先执行异步操作,再await等待结果
- 也可以通过Promise.all让异步操作并发执行
版权归原作者 来自爪哇的bean 所有, 如有侵权,请联系我们删除。