实践总结-网络传输

http 的 POST 提交方式

http1.1 规定 http 请求方式有 options,get,head,post,put,delete,trace,connect 几种

服务端会根据前端 http 请求发送的请求头的 Content-Type 字段来获取请求中的消息主体是用何种方式编码,在对主体进行解析。所以 POST 提交数据方案,包含了 Content-Type 和消息主体编码方式两部分

js 复制代码
let xhr = new XMLHttpRequest()
xhr.open("post", "http://127.0.0.1:80")
xhr.setRequestHeader(
  "Content-Type",
  "application/x-www-form-urlencoded;charset=utf-8"
)
xhr.send()
application/x-www-form-urlencode

目前最常见的 POST 提交数据方案,浏览器原生的 form 表单,如果不设置 enctype 属性,那么最终会 application/x-www-form-urlencode 方式提交数据 提交数据的格式按照(key=value)

js 复制代码
xhr.setRequestHeader(
  "Content-Type",
  "application/x-www-form-urlencoded;charset=utf-8"
)
let data = "key1=123&key2=345"
xhr.send(data)
multipart/form-data
js 复制代码
xhr.setRequestHeader("Content-Type":"multipart/form-data")

常见的 form 提交格式。我们使用 form 表单上传文件的时候,必须要让 enctype 等于 multipart/form-data

application/json

目前除了低版本的 ie 浏览器,其他浏览器都支持原生的 JSON.stringify,服务端语言也都有处理 JSON 的函数,使用 JSON 不会遇上什么麻烦。 JSON 格式支持比键值对复杂得多的结构化数据。

js 复制代码
xhr.setRequestHeader("Content-Type":"multipart/form-data")
text/xml

它是一种使用 HTTP 作为传输协议,XML 作为编码方式的远程调用规范

表单的提交方式

  1. application/json

  2. multipart/form-data 这种格式不能直接设置"Content-Type"="multipart/form-data" 因为你手动设置了它,那么后面这个 boundary=浏览器默认 boundary 就没了

js 复制代码
form.append("name", "leiwuyi")
form.append("age", 12)
request
  .post("/simu/wechat/voucherList")
  .send(form)
  .then((res) => {})
  1. text/plain 是纯文本格式 如果你发送一个对象例如{ name:"leiwuyi", age:12 }一定要对它做 JSON.stringfiy()处理
js 复制代码
request
  .post("/simu/wechat/voucherList")
  .set("Content-Type", "text/plain")
  .send("age=12")
  .then((res) => {})

http 缓存机制

一般样式表会缓存在磁盘中,不会缓存到内存中,因为 css 样式加载一次即可渲染出页面。但是脚本可能会随时执行,如果把脚本存在磁盘中,在执行时会把该脚本从磁盘中提取到缓存中来,这样的 IO 开销比较大,有可能会导致浏览器失去响应。所以一般将 html+css 缓存在磁盘上,js 存放在内存里。

NetWork 返回的状态码

200 form memory cache 不访问服务器,一般已经加载过该资源且缓存在了内存当中,直接从内存中读取缓存。浏览器关闭后,数据将不存在(资源被释放掉了),再次打开相同的页面时,不会出现 from memory cache。

200 from disk cache 不访问服务器,已经在之前的某个时间加载过该资源,直接从硬盘中读取缓存,关闭浏览器后,数据依然存在,此资源不会随着该页面的关闭而释放掉下次打开仍然会是 from disk cache。

304 Not Modified 访问服务器,发现数据没有更新,服务器返回此状态码。然后从缓存中读取数据。

浏览器 Network 缓存

在浏览器开发者工具的 Network 的 Size 栏会出现的三种情况: from memory cache from disk cache 资源本身大小(比如:13.6K)

三级缓存原理 1、先查找内存,如果内存中存在,从内存中加载; 2、如果内存中未查找到,选择硬盘获取,如果硬盘中有,从硬盘中加载; 3、如果硬盘中未查找到,那就进行网络请求; 4、加载到的资源缓存到硬盘和内存;

强缓存

  1. Expires:response header 里面的过期时间,浏览器再次加载资源时,浏览器再次加载资源时,如果在这个过期时间内,则命中强缓存。
  2. Cache-Control:dab===当值设为 max-age=300 时,则代表在这个请求正确返回时间的 5 分钟内再次加载资源就会命中强缓存。

区别:Expires 是 http1.0 的产物,Cache-Control 是 http1.1 的产物,两者同时存在的话,Cache-Control 优先级高于 Expires,Expires 是过时的写法,现阶段它的存在只是一种兼容性写法

协商缓存

  1. ETag 和 IF-None-Match Etag 是上一次加载资源时,服务器返回的 response header,是对该资源的一种唯一标识,只要资源有变化,Etag 就会重新生成。览器在下一次加载资源向服务器发送请求时,会将上一次返回的 Etag 值放到 request header 里的 If-None-Match 里。服务器接受到 If-None-Match 的值后,会拿来跟该资源文件的 Etag 值做比较,如果相同,则表示资源文件没有发生改变,命中协商缓存。

  2. Last-Modified 和 If-Modified-Since Last-Modified 是该资源文件最后一次更改时间,服务器会在 response header 里返回。同时浏览器会将这个值保存起来,下一次发送请求时,放到 request headr 里的 If-Modified-Since 里

区别:在精确度上,Etag 要优于 Last-Modified,Last-Modified 的时间单位是秒,如果某个文件在 1 秒内改变了多次,那么他们的 Last-Modified 其实并没有体现出来修改,但是 Etag 每次都会改变确保了精度 在性能上,Etag 要逊于 Last-Modified,毕竟 Last-Modified 只需要记录时间,而 Etag 需要服务器通过算法来计算出一个 hash 值。在优先级上,服务器校验优先考虑 Etag。所以,两者互补

用户行为对 http 缓存的控制

  1. 地址栏访问:链接跳转是正常用户行为,将会触发浏览器缓存机制【浏览器发起请求,按照正常流程,本地检查是否过期,或者服务器检查新鲜度,最后返回内容】

  2. F5 刷新:浏览器会设置 max-age=0,跳过强缓存判断,会进行协商缓存判断【浏览器直接对本地的缓存文件过期,但是会带上 If-Modifed-Since,If-None-Match(如果上一次 response 带 Last-Modified, Etag)这就意味着服务器会对文件检查新鲜度,返回结果可能是 304,也有可能是 200.】

  3. ctrl+F5 刷新:跳过强缓存和协商缓存,直接从服务器拉取资源。【浏览器不仅会对本地文件过期,而且不会带上 If-Modifed-Since,If-None-Match,相当于之前从来没有请求过,返回结果是 200.】

禁止缓存

  1. Cache-Control 字段值: no-cache, no-store, must-revalidate
  2. 前端开发设置不缓存:
html 复制代码
<meta http-equiv="Cache-Control" content="no-cache, must-revalidate">
<meta http-equiv="expires" content="Wed, 26 Feb 1997 00:00:00 GMT">

浏览器下载文件

浏览器不支持的文档类型,默认会下载。那对于能处理的那些类型呢?比如图片,js,json 等内容呢?

关于浏览器是预览图片还是下载图片,这里有一个比较标准的结论了。如果是同源文件(图片/txt),那么浏览器会直接走下载的逻辑,如果非同源文件,那么如果浏览器能打开那么会直接打开预览而不是走下载逻辑。

Content-Type(内容类型),一般是指网页中存在的 Content-Type,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件,这就是经常看到一些 PHP 网页点击的结果却是下载一个文件或一张图片的原因。

Content-Type 标头告诉客户端实际返回的内容的内容类型。

js 复制代码
"Content-Type":" text/html; charset=utf-8"//html文件
"Content-Type":"application/pdf"//pdf格式
"Content-Type":"image/jpeg"//图片文件
"Content-Type":"application/zip"//zip文件

前端实现下载的方式主要是静态文件直接下载和文件流下载:

直接下载就是根据浏览器的下载策略直接下载文件,在浏览器的文件请求中的 Content-Type 可以获取到文件的类型,如果是 pdf,jpg 之类的文件,根据浏览器的文件策略会将直接执行预览策略

直接下载

  1. 最简单的方式就是:在后端的代码中设置 Content-Type:application/octet-stream 会将文件识别为文件流,自动执行下载操作

  2. 通过一个 get 请求将静态文件转换为文件流在进行下载,动态创建 a 标签

js 复制代码
const xhr = new XMLHttpRequest()
xhr.open("GET", "http://localhost:3001/001.pdf")
xhr.responseType = "blob"//设置数据返回类型


//ajax的onreadystatechange事件
xhr.onreadystatechange()=>{
  if(xhr.readyState===4&&xhr.status===200){
       let blob=new Blob([xhr.responseText])
      let link= docoment.createElement("a")
      link.download="filename"
      line.style.display="none"
       // a.setAttribute("href", fileUrl)
      // a.setAttribute("download", fileName)
      link.href=URL.createObjectURL(blob)
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
  }
}
//ajax的加载事件,使用的是创建一个本地静态url地址进行下载
// xhr.onload = function () {
//   const blob = xhr.response
//   const url = URL.createObjectURL(blob)
//   downloadAs(url, "mypack.zip")
//   URL.revokeObjectURL(url)
// }

//发送请求
xhr.send()
相关推荐
陈随易4 分钟前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马15 分钟前
前沿视界
前端
kyriewen19 分钟前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
陈随易36 分钟前
3000 万人在用的翻译插件,重写一遍就是一门生意
前端·后端·程序员
IT_陈寒43 分钟前
Vue的这个响应式陷阱,差点让我加班到天亮
前端·人工智能·后端
Flynt2 小时前
别写拖拽行为,只声明"能拖到哪":UIST 最佳论文的拖拽方案我实测了
前端·svg·preact
Moment3 小时前
代码都能让 Agent 写了,我们为什么还要学前端?
前端·后端·面试
Hilaku3 小时前
MCP 协议会成为前端 AI 工程的标准接口吗?
前端·javascript·程序员
Zan3 小时前
Tauri 2 实战:为什么一个可靠的桌面应用,应该由 Rust Host 管理生命周期?
前端·架构·rust
SameX3 小时前
鸿蒙 ArkTS 独立开发者的项目结构 model / dao / viewmodel / page / common 的分层
前端