# HTTP 协议请求报文、响应
一个 HTTP 请求报文可以由请求行、请求头、空行和请求体 4 个部分组成。
一个 HTTP 响应报文是由响应行、响应头、空行和响应体 4 个部分组成。
(报文 (message) 是网络中交换与传输的数据单元)
https://zhuanlan.zhihu.com/p/533284035 (超详细的 HTTP 协议请求报文、响应报文教程)
#
# JSON
# 什么是 json
JSON 是一种轻量级的数据交互格式。可以按照 JSON 指定的格式去组织和封装数据
JSON 本质上是一个带有特定格式的字符串
主要功能:json 就是一种在各个编程语言中流通的数据格式,负责不同编程语言中的数据传递和交互。类似于:
国际通用语言 - 英语
中国 56 个民族不同地区的通用语言 - 普通话
# json 有什么用
各种编程语言存储数据的容器不尽相同,在 Python 中有字典 dict 这样的数据类型,而其它语言可能没有对应的字典。
为了让不同的语言都能够相互通用的互相传递数据,JSON 就是一种非常良好的中转数据格式。
# json 格式数据转化
# json数据的格式可以是: | |
{"name":"admin","age":18} 是{}括起来的键值对 | |
# 也可以是: | |
[{"name":"admin","age":18},{"name":"root","age":16},{"name":"张三","age":20}] | |
是[]括起来的元素 | |
可以嵌套 |
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> | |
<dependency> | |
<groupId>com.alibaba</groupId> | |
<artifactId>fastjson</artifactId> | |
<version>2.0.39</version> | |
</dependency> |
Java 中:java 转 json 字符串
String jsonStr = JSON.toJSONString(objs); |
JS 中:json 字符串转 JavaScript 对象
JSON.parse(this.responseText) |
#
# Ajax
Ajax(Asynchronous JavaScript And XML)即异步 JavaScript 和 XML,是一组用于在网页上进行异步数据交换的 Web 开发技术,可以在不刷新整个页面的情况下向服务器发起请求并获取数据,然后将数据插入到网页中的某个位置。这种技术能够实现增量式更新页面,提高用户交互体验,减少响应时间和带宽的消耗。
# 优点
- 提升用户体验(通过减少页面的重载和刷新,使得网站变得更加灵活和的动态)
- 减轻服务器压力(通过 Ajax 可以有效减少服务器接收到的请求次数和需要响应的数据量)
- 提高响应速度(异步获得数据并更新页面)
- 增加交互性(页面变得动态性和交互性)
# 缺点
- Ajax 对 SEO(搜索引擎优化不友好)
- 使用 Ajax 时,需要考虑数据安全性和网络安全性,并采取相应的措施防范
#
# XMLHttpRequest
# 使用
使用 XMLHttpRequest
可以通过 JavaScript 发起 HTTP 请求,接收来自服务器的响应,并动态地更新网页中的内容。这种异步通信方式不会阻塞用户界面,有利于增强用户体验。
// 发送 get 请求 | |
const xhr = new XMLHttpRequest(); | |
xhr.open('GET', 'http://localhost:3000/api/txt') | |
xhr.onload = function() { | |
if (xhr.status === 200) { | |
document.querySelector('#result').innerText = xhr.responseText; | |
} | |
else { | |
console.log('Request failed. Returned status of ' + xhr.status); | |
} | |
}; | |
xhr.send(null); | |
// 发送 post 请求 | |
const xhr = new XMLHttpRequest(); | |
xhr.open('POST', 'http://localhost:3000/api/post') | |
xhr.setRequestHeader('Content-Type', 'application/json'); | |
xhr.onload = function() { | |
if (xhr.status === 200) { | |
document.querySelector('#result').innerText = xhr.responseText; | |
} | |
else { | |
console.log('Request failed. Returned status of ' + xhr.status); | |
} | |
}; | |
xhr.send(JSON.stringify({name: 'zhangsan', age: 18})); |
# 中断请求
xhr 通过 addEventListener 事件监听的机制来进行请求的中断和超时处理。
xhr.addEventListener('abort', function (event) { | |
console.log('我被中断了'); | |
}); |
# 超时时间
xhr.addEventListener('timeout', function (event) { | |
console.log('超时啦'); | |
}); |
# 监听进度
xhr 中的监听进度可以获得全过程的进行进度,这是 fetch 这个 api 所没有的
xhr.addEventListener('progress', function (event) { | |
document.querySelector('#progress').innerText = `${(event.loaded / event.total * 100).toFixed(2)}%`; | |
}); |
#
# Fetch
# 使用
fetch 返回格式:
text (): 将响应体解析为纯文本字符串并返回。
json (): 将响应体解析为 JSON 格式并返回一个 JavaScript 对象。
blob (): 将响应体解析为二进制数据并返回一个 Blob 对象。
arrayBuffer (): 将响应体解析为二进制数据并返回一个 ArrayBuffer 对象。
formData (): 将响应体解析为 FormData 对象。
//get 请求 | |
fetch('http://localhost:3000/api/txt').then(res => { | |
console.log(res); | |
return res.text() | |
}).then(res => { | |
console.log(res); | |
}) | |
//post 请求 | |
fetch('http://localhost:3000/api/post',{ | |
method:'POST', | |
headers:{ | |
'Content-Type':'application/json' | |
}, | |
body:JSON.stringify({ | |
name:'zhangsan', | |
age:18 | |
}) | |
}).then(res => { | |
console.log(res); | |
return res.json() | |
}).then(res => { | |
console.log(res); | |
}) |
# 中断请求
使用 AbortController
的 abort
方法中断
const abort = new AbortController() | |
fetch('http://localhost:3000/api/post',{ | |
method:'POST', | |
headers:{ | |
'Content-Type':'application/json' | |
}, | |
signal:abort.signal, | |
body:JSON.stringify({ | |
name:'zhangsan', | |
age:18 | |
}) | |
}).then(res => { | |
console.log(res); | |
return res.json() | |
}).then(res => { | |
console.log(res); | |
}) | |
document.querySelector('#stop').addEventListener('click', () => { | |
console.log('stop'); | |
abort.abort() | |
}) |
# 获取进度
使用 data.clone () 方法复制了响应对象 data,然后使用 getReader () 方法获取数据流中的 reader 对象,接着通过读取数据流并计算已加载字节数,实现了一个基于原生 JavaScript 的进度条功能。
const btn = document.querySelector('#send') | |
const sendFetch = async () => { | |
const data = await fetch('http://localhost:3000/api/txt',{ | |
signal:abort.signal | |
}) | |
//fetch 实现进度条 | |
const response = data.clone() | |
const reader = data.body.getReader() | |
const contentLength = data.headers.get('Content-Length') | |
let loaded = 0 | |
while (true) { | |
const { done, value } = await reader.read() | |
if (done) { | |
break | |
} | |
loaded += value?.length || 0; | |
const progress = document.querySelector('#progress') | |
progress.innerHTML = (loaded / contentLength * 100).toFixed(2) + '%' | |
} | |
const text = await response.text() | |
console.log(text); | |
} | |
btn.addEventListener('click', sendFetch) |
# 携带 cookie
const data = await fetch('http://localhost:3000/api/txt',{ | |
signal:abort.signal, | |
//cookie | |
credentials:'include', | |
}) |
# Fetch 和 XMLHTTPRequest 对比
fetch
和 XMLHttpRequest
(XHR)都是前端与服务器进行数据交互的常用方式,它们各有优缺点,下面是它们的比较:
- API 设计和使用方式
fetch
的 API 设计更加现代化、简洁和易于使用,使用起来更加直观和方便。相比之下,XHR 的 API 设计比较繁琐,需要进行多个参数的配置和回调函数的处理。
- 支持的请求方法
fetch
API 默认只支持 GET 和 POST 请求方法,而 XHR 则支持所有标准的 HTTP 请求方法。
- 请求头部
在 fetch
中设置请求头部的方式更加清晰和直接,可以通过 Headers
对象进行设置,而 XHR 的方式相对较为繁琐。
- 请求体
在发送 POST 请求时, fetch
API 要求将请求体数据作为参数传递给 fetch
方法中的 options
对象,而 XHR 可以直接在 send()
方法中设置请求体数据。
- 支持的数据类型
在解析响应数据时, fetch
API 提供了多种方法,包括 .json()
, .blob()
, .arrayBuffer()
等,而 XHR 只支持文本和二进制数据两种数据类型。
- 跨域请求
在进行跨域请求时, fetch
API 提供了一种简单而强大的解决方案 —— 使用 CORS(跨域资源共享)头部实现跨域请求,而 XHR 则使用了一个叫做 XMLHttpRequest Level 2
的规范,在代码编写上相对较为繁琐。
总的来说, fetch
API 与 XHR 各有优缺点,具体选择哪种方式还需要根据具体情况进行考虑。平时开发中使用较多的是 fetch
,因为它使用方便、API 简洁、语法清晰,同时也支持了大多数常用的功能,可以有效地简化前端开发流程。
#
# axios
专注与网络请求的库
相比于原生的 XMLHttpRequest 对象,axios 简单易用
相比与 jQuery,axios 更加轻量化,只专注与网络数据请求
# axios 发起 GET 请求:
var url='' | |
var paramsObj={name:'zs',age:20} | |
axios.get(url,{params:paramsObj}) | |
.then(function(res){ | |
console.log(res) | |
//res.data 服务器响应的数据 | |
console.log(res.data) | |
}) |
# axios 发起 POST 请求:
var url='http://' | |
var dataObj={location:'Beijing',address:'haidian'} | |
axios.post(url,dataObj) | |
.then(function(res){ | |
console.log(res) | |
//res.data 服务器响应的数据 | |
console.log(res.data) | |
}) |
# 直接使用 axios 发起请求:
axios 页提供了类似于 jQuery 中的 $.ajax () 的函数,语法如下:
axios({ | |
method:'GET' | |
url:'' | |
//GET 参数要通过 params 属性提供 | |
params:{name:'zs',age:20} | |
}) | |
.then(function(res){ | |
console.log(res.data) | |
}) | |
------------------------------------- | |
axios({ | |
method:'POST' | |
url:'' | |
//POST 参数要通过 data 属性提供 | |
data:{bookname:'thinking java',price:20} | |
}) | |
.then(function(res){ | |
console.log(res.data) | |
}) |
#
# navigator.sendBeacon
// 性能中继器,使用不同指标来衡量和分析应用程序的性能 | |
// 当页面上任何指标值完成计算时,将传递计算出的结果并触发这个函数 | |
// 可以使用它将结果记录到控制台或者发送到特定端点 | |
function sendTo(metric){ | |
const content = JSON.stringify(metric); | |
if(navigator.sendBeacon){ | |
navigator.sendBeacon('http://test',content); //navigator.sendBeacon 的作用是 | |
}else{ | |
fetch('http://test.com',{ | |
content, | |
method:'POST', | |
keepAlive:true //fetch 中的 keepAlice 保证了即使页面刷新或者关闭,发出的请求仍然存在并进行,而不是进行到一半的请求突然停止 | |
}).then(()=>{ | |
console.log('发送成功'); | |
}).catch((e)=>{ | |
console.error(e); | |
}) | |
} | |
} | |
reportWebVitals(sendTo); // 每一次得到计算结果都会执行一次 |
# 对比 Ajax fetch
# 优点
- 不受页面卸载过程的影响,确保数据可靠发送。
- 异步执行,不阻塞页面关闭或跳转。
- 能够发送跨域请求。
# 缺点
- fetch 和 ajax 都可以发送任意请求 而 sendBeacon 只能发送 POST
- fetch 和 ajax 可以传输任意字节数据 而 sendBeacon 只能传送少量数据(64KB 以内)
- fetch 和 ajax 可以定义任意请求头 而 sendBeacon 无法自定义请求头
- sendBeacon 只能传输
ArrayBuffer
、ArrayBufferView
、Blob
、DOMString
、FormData
或URLSearchParams
类型的数据 如果处于危险的网络环境,或者开启了广告屏蔽插件 此请求将无效
# 应用场景
- 发送心跳包:可以使用
navigator.sendBeacon
发送心跳包,以保持与服务器的长连接,避免因为长时间没有网络请求而导致连接被关闭。 - 埋点:可以使用
navigator.sendBeacon
在页面关闭或卸载时记录用户在线时间,pv uv,以及错误日志上报 按钮点击次数。 - 发送用户反馈:可以使用
navigator.sendBeacon
发送用户反馈信息,如用户意见、bug 报告等,以便进行产品优化和改进