15分钟巩固你的HTTP知识体系,和谁扯皮都没问题
一、简介
前端工程师打交道最多的就是浏览器,不管做什么都离不开浏览器,其中HTTP协议往往会被我们忽略,但其实资源缓存、CDN加载、页面性能优化等等都离不开对HTTP协议的了解。
最简单的例子:
- 输入url打开网页
- AJAX获取数据
- img标签加载图片
从输入URL到看到页面发生了什么?
DNS解析
发起TCP连接
发送HTTP请求
服务器处理请求并返回HTTP报文
浏览器解析渲染页面
连接结束。
其实,我们了解这个过程对前端的性能优化是有意义的,在这个过程中找到优化点,去缩短请求的时间,从而去加快web前端的访问速度,提升性能
详细参考:https://juejin.cn/post/6844903832435032072
二、HTTP协议基础及发展历史
HTTP协议的发展历史
http/0.9:
(1)只有一个命令get
(2)没有header等描述数据的信息
(3)服务器发送完毕就关闭TCP连接
http/1.0:
(1)增加了很多命令(如get、post、put、delete、head等)
(2)增加响应状态码和header数据描述信息
(3)多字符集支持、多部分发送、权限、缓存等
http/1.1:
(1)持久链接(http1.0中每发起一次http请求,就要进行一次TCP连接;减少三次握手的消耗,提高性能 tcp 建立服务器与客户端的连接不再关闭)
(2)pipeline(一次TCP连接可以发送多个http请求,但是服务端同一时间只能处理一个http请求,处理完成后才能处理下一个请求,即服务端处理请求是串行的)
(3)增加host与其他一些命令(增加了host头部字段,可以在同一物理服务器上跑多个不同Web服务器)
http/2.0:
(1)所有数据以二进制传输
(2)同一个连接里面发送多个请求不再需要按照顺序来,即服务端处理请求是并行的
(3)对头部字段进行压缩,减少带宽占用量;及推送功能(服务端可以主动发送信息,根据http请求的HTML的文件主动推送文件中需要用到的js文件和css文件,不用等到客户端解析渲染时再请求,大大提高了效率)
创建一个http服务
HTTP的三次握手
http是不存在连接这个概念的,只有请求与相应
请求和响应都是数据包,需要一个传输的通道,这个通道由TCP创建。
为什么要进行一个三次握手:
防止服务端这边开启一些无用的连接。
网络传输是有延迟的,中间可能隔了很远的距离,要通过光纤、还有中间的各种代理服务器来进行一个传输;
传输过程中客户端发起了一个SYN=1的创建连接请求,如果服务端直接创建了这个连接,然后返回内容给客户端,此时由于网络传输的原因数据包丢失了,客户端就一直没接收到服务器返回的内容,客户端可能会有超时时间,会关闭这个连接创建。然后再发起一个新的创建连接请求
如果没有三次握手的话服务端是不知道 客户端到底有没有收到也没有一个返回的信息确认来创建还是关闭这个连接,这个端口就会一直开着 造成资源的浪费
三次就是为了确定请求的ok,规避由于网络延迟的服务器开销问题
采用两次握手为什么不行
原因就是上面说的失效的连接请求的特殊情况。而在三次握手中, client和server都有一个发syn和收ack的过程, 双方都是发后能收, 表明通信则准备工作OK。
为什么不是四次握手呢?
大家应该知道通信中著名的蓝军红军约定, 这个例子说明, 在不可靠通信信道上无法设计出一种完全可靠的通信协议,通信不可能100%可靠, 而上面的三次握手已经做好了通信的准备工作, 再增加握手, 并不能显著提高可靠性, 而且也没有必要。
URI-URL和URN
scheme 表示协议名,比如http, https, file等等。后面必须和://连在一起。
user:passwd@ 表示登录主机时的用户信息,不过很不安全,不推荐使用,也不常用。
host:port表示主机名和端口。
path表示请求路径,标记资源所在位置。
query表示查询参数,为key=val这种形式,多个键值对之间用&隔开。
fragment表示 URI 所定位的资源内的一个锚点,浏览器可以根据这个锚点跳转到对应的位置。
举个例子:
https://www.baidu.com/swd=HTTP&rsv_spt=1
复制代码这个 URI 中,
https即scheme部分,
www.baidu.com为host:port部分(注意,http 和 https 的默认端口分别为80、443),
/s为path部分,
而wd=HTTP&rsv_spt=1就是query部分。
报文格式
请求报文:方法 + 路径 + http版本
响应报文:http版本+状态码+原因
HTTP 请求方法
- GET: 通常用来获取资源
- HEAD: 获取资源的元信息
- POST: 提交数据,即上传数据
- PUT: 修改数据
- DELETE:删除资源(几乎用不到)
- CONNECT: 建立连接隧道,用于代理服务器
- OPTIONS: 列出可对资源实行的请求方法,用来跨域请求
- TRACE: 追踪请求-响应的传输路径
code
100~199 操作需要持续进行
200~299 代表操作成功
300~399 需要重定向
400~499 代表请求有问题
500~599 服务端有错误
三、HTTP各种特性总览
什么是跨域?浏览器如何拦截响应?如何解决?
在前后端分离的开发模式中,经常会遇到跨域问题,即 Ajax 请求发出去了,服务器也成功响应了,前端就是拿不到这个响应。
浏览器遵循同源政策(scheme(协议)、host(主机)和port(端口)都相同则为同源)。非同源站点有这样一些限制:
不能读取和修改对方的 DOM
不读访问对方的 Cookie、IndexDB 和 LocalStorage
限制 XMLHttpRequest 请求。
解决跨域的几种方法
1.CORS
‘Access_Control_Allow_Origin’ : *
这是浏览器对复杂跨域请求的一种处理方式,在真正发送请求之前,会先进行一次预请求,就是我们刚刚说到的参数为OPTIONS的第一次请求,他的作用是用于试探性的服务器响应是否正确,即是否能接受真正的请求,如果在options请求之后获取到的响应是拒绝性质的,例如500等http状态,那么它就会停止第二次的真正请求的访问
演示
2.JSONP
利用link标签,src标签可以进行跨域
虽然XMLHttpRequest对象遵循同源政策,但是script标签不一样,它可以通过 src 填上目标地址从而发出 GET 请求,实现跨域请求并拿到响应。这也就是 JSONP 的原理
和CORS相比,JSONP 最大的优势在于兼容性好,IE 低版本不能使用 CORS 但可以使用 JSONP,缺点也很明显,请求方法单一,只支持 GET 请求。
3.Nginx
Nginx 是一种高性能的反向代理服务器,可以用来轻松解决跨域问题。
正向代理帮助客户端访问客户端自己访问不到的服务器,然后将结果返回给客户端。
反向代理拿到客户端的请求,将请求转发给其他的服务器,主要的场景是维持服务器集群的负载均衡,换句话说,反向代理帮其它的服务器拿到请求,然后选择一个合适的服务器,将请求转交给它。
那 Nginx 是如何来解决跨域的呢?
比如说现在客户端的域名为client.com,服务器的域名为server.com,客户端向服务器发送 Ajax 请求,当然会跨域了,那这个时候让 Nginx 登场了,通过下面这个配置:
server {
listen 80;
server_name client.com;
location /api {
proxy_pass server.com;
}
}
Nginx 相当于起了一个跳板机,这个跳板机的域名也是client.com,让客户端首先访问 client.com/api,这当然没有跨域,然后 Nginx 服务器作为反向代理,将请求转发给server.com,当响应返回时又将响应给到客户端,这就完成整个跨域请求的过程。
缓存头Cache-Control的含义和使用
一、可缓存性(哪些地方可以缓存):
public(任何地方都可以),
private(发起请求的浏览器可以进行缓存),
no-cache(本地可以存缓存,但是需要等待服务器验证后才可以使用)
二:时间限制:
max-age = ,
s-max-age = (只在代理服务器生效 ,缓存到期时间),
max-stale = (使用过期的缓存(服务器))
三:重新验证:
1.must-revalidate(时间过期必须去原服务端重新获取数据),
2.proxy-revalidate(和must-revalidate类似,用于缓存服务器中)
其他
no store (任何地方都不可以缓存)
no transform (主要是用在代理服务器,告诉代理服务器不要随便改动返回的内容 比如一些东西他觉得太大了 可能会压缩)
这些头只是一个声明性、限制性的一个作用
服务器它也完全可以不按照这个配置去做
前端无法设置cache-Control,这个是只有在请求返回的时候才能设置的
前端开发中常见的问题
Cache-control是客户端缓存,如果设置了cache-control,它就直接在客户端缓存了 不会经过服务端去验证,所以当服务端更新了文件之后,客户端并不知道文件更新了,它还会继续从缓存中读取,就导致了服务端上一些静态资源(js,css,图片等)更新了之后没有及时的更新到客户端
解决:一般会在打包完成的js文件名加上hash码, 根据内容生成一串hash码。
演示
缓存验证Last-Modified和Etag的使用
缓存综述:
Cookie
- 通过Set-Cookie设置
- 下次请求会自动带上
- max-age和expires设置过期时间
- Secure只在https的时候发送
- HttpOnly无法通过document.cookie访问
- domain访问域设定
cookie只能一个域访问
a.com的cookie b.com不能访问
domain让a.test.com能访问test.com的cookie
不能跨域设置cookie,只能一级通过domain设置二级等
长连接
从 HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头有加入这行代码:Connection:keep-alive 在 使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的 TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件中设定这个时间。 HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。 如图可以通过chrome右键新增connectionID来判断资源是否使用的同一个连接
http1.1里一个TCP连接的http请求时有先后顺序的,只有等前面一个请求完成后,才可以进行下一个请求,因此为了优化网页显示速度,一般都并发开启TCP连接,每个网站的TCP连接的并发数是有限制的(6个)。
http2.0里一个TCP连接可以并发发出http请求,因此如果使用http2.0可以实现一个网站只使用一个TCP连接(限制:同源网站),减少网络资源消耗(如三次握手。。。),示例:谷歌网站
响应头、请求头设置Connection:keep-alive。表示协商的过程,是否建立长链接
只有同域的connextion ID 会出现同一个
设置connection:close,每次都要重现建立tcp连接,所以connect ID都是不一样
http2:信道复用 tcp并发发送http请求
http请求是在tcp上发送的,一个tcp可以发送多个http,http1.1是阻塞的
数据协商
数据协商就是客户端发个服务端一个请求,服务端根据客户端的要求返回对应的数据
Accept(浏览器希望服务器返回的数据格式)
Accept-Enconding:服务器返回的数据是通过哪种方式被压缩的,比如值为gzip,那么浏览器就希望数据是通过gzip这种方式压缩的。(gzip,defalte,br)
Accept-Language:浏览器希望服务器返回的语言。
User-Agent:浏览器和系统的相关信息,比如是移动端的浏览器还是pc端浏览器
redirect
redirect:重定向,通过url访问一个资源时,如果在服务器上没找到这个url地址指向的资源,那么服务器会给浏览器重新发送一个地址,告诉浏览器这个资源在哪里,接着浏览器就会重新请求重新发送的地址。
Location:指定跳转的路由地址。
状态码:301,永久跳转(我会直接通过浏览器跳转到这个地址,是从浏览器的缓存中读取,哪怕服务器更改了状态码或者跳转地址,浏览器都无法感知,只能看用户何时清浏览器缓存,需要特别谨慎使用);302,临时跳转(下次跳转的就不一定是这个地址了)
HTTPS解析
加密方式:
1.对称加密:一个key同时负责加密、解密;
2.非对称加密:一对key,A加密之后,只能用B来解密
中间人攻击
https证书
浏览器校验证书
使用第三方证书
总结
写到这里也结束了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个关于 前端开发 的学习思路及方向。从事互联网开发,最主要的是要学好技术,而学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯,更加需要准确的学习方向达到有效的学习效果。
由于内容较多就只放上一个大概的大纲,需要更及详细的学习思维导图的 点击我的GitHub免费获取。
还有免费的 高级web全套视频教程 前端架构 H5 vue node 小程序 视频+资料+代码+面试题!
全方面的web前端进阶实践技术资料,并且还有技术大牛一起讨论交流解决问题。