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 作为编码方式的远程调用规范
表单的提交方式
-
application/json
-
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) => {})
- 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、加载到的资源缓存到硬盘和内存;
强缓存
- Expires:response header 里面的过期时间,浏览器再次加载资源时,浏览器再次加载资源时,如果在这个过期时间内,则命中强缓存。
- Cache-Control:dab===当值设为 max-age=300 时,则代表在这个请求正确返回时间的 5 分钟内再次加载资源就会命中强缓存。
区别:Expires 是 http1.0 的产物,Cache-Control 是 http1.1 的产物,两者同时存在的话,Cache-Control 优先级高于 Expires,Expires 是过时的写法,现阶段它的存在只是一种兼容性写法
协商缓存
-
ETag 和 IF-None-Match Etag 是上一次加载资源时,服务器返回的 response header,是对该资源的一种唯一标识,只要资源有变化,Etag 就会重新生成。览器在下一次加载资源向服务器发送请求时,会将上一次返回的 Etag 值放到 request header 里的 If-None-Match 里。服务器接受到 If-None-Match 的值后,会拿来跟该资源文件的 Etag 值做比较,如果相同,则表示资源文件没有发生改变,命中协商缓存。
-
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 缓存的控制
-
地址栏访问:链接跳转是正常用户行为,将会触发浏览器缓存机制【浏览器发起请求,按照正常流程,本地检查是否过期,或者服务器检查新鲜度,最后返回内容】
-
F5 刷新:浏览器会设置 max-age=0,跳过强缓存判断,会进行协商缓存判断【浏览器直接对本地的缓存文件过期,但是会带上 If-Modifed-Since,If-None-Match(如果上一次 response 带 Last-Modified, Etag)这就意味着服务器会对文件检查新鲜度,返回结果可能是 304,也有可能是 200.】
-
ctrl+F5 刷新:跳过强缓存和协商缓存,直接从服务器拉取资源。【浏览器不仅会对本地文件过期,而且不会带上 If-Modifed-Since,If-None-Match,相当于之前从来没有请求过,返回结果是 200.】
禁止缓存
- Cache-Control 字段值: no-cache, no-store, must-revalidate
- 前端开发设置不缓存:
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 之类的文件,根据浏览器的文件策略会将直接执行预览策略
直接下载
-
最简单的方式就是:在后端的代码中设置
Content-Type:application/octet-stream
会将文件识别为文件流,自动执行下载操作 -
通过一个 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()