学习 HTTP 协议笔记
网络模型
五层网络模型:
OSI 七层模型是国际标准化组织的标准,由于前者过于复杂且指定周期长,在整套标准推出之前,TCP/IP 模型就已经在全球范围内被广泛使用了,所以TCP/IP模型成了事实上的国际标准。我们在学习和开发中,将两者结合,这就是五层网络模型。
协议举例及功能
应用层
功能:为应用软件提供了很多服务。
协议: HTTP、DNS、FTP(文件传输)、SSH、Telnet、SMTP(电子邮件)
传输层
功能:向用户提供可靠的端到端服务。
协议: TCP、UDP
网络层
功能:寻址、路由。
协议:IPV4、IPV6、RARP、ICMP(V4、V6)
设备:路由器、三层交换机
数据链路层
功能:在通信实体间建立数据链路连接。
协议:以太网、Wi-Fi
设备:网卡、交换机
物理层
功能:定义物理设备如何传输数据。
设备:光纤、集线器、RJ-45接头
HTTP 协议发展历史
HTTP/0.9
HTTP 最早版本是1991年发布的0.9版本。该版本有如下特点:
- 只有一个命令
GET
。 - 没有
HEADER
等描述数据的信息。 - 协议规定,服务器只能回应HTML格式的字符串,不能回应别的格式。
- 服务器发送完毕,就关闭TCP连接。
HTTP/1.0
1996年5月,HTTP/1.0发布,内容大大增加:
- 任何格式的内容都可以发送。
- 新增
POST
和HEAD
命令。 - 每次通信都必须包含头信息(HTTP header)。
- 新增状态码(status code)。
- 新增多字符集支持、多部分发送(multi-part type)、权限(authorization)、缓存(cache)、内容编码(content encoding)等。
HTTP/1.1
1997年1月,HTTP/1.1 版本发布,至今(2020年)仍是最流行的版本。新增的功能有:
1. 持久连接(persistent connection)
即TCP连接默认不关闭,可以被多个请求复用。默认开启Connection: keep-alive
。
客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送Connection:close
,明确要求服务器关闭TCP连接。
目前,对于同一个域名,大多数浏览器允许同时建立6个持久连接。
2. 管道机制(pipelining)
即在同一个TCP连接里面,客户端可以同时发送多个请求。
举例来说,客户端需要请求两个资源。以前的做法是,在同一个TCP连接里面,先发送A请求,然后等待服务器做出回应,收到后再发出B请求。管道机制则是允许浏览器同时发出A请求和B请求,但是服务器还是按照顺序,先回应A请求,完成后再回应B请求。
3. 其他
新增动词方法:PUT
、PATCH
、OPTIONS
、DELETE
客户端请求头新增Host
字段,用来指定服务器的域名。
1 | Host: www.example.com |
有了Host
字段,就可以将请求发往同一台服务器上的不同网站。虚拟主机技术就是利用的这一点。在apache,ngnix环境下,直接通过配置文件cfg文件来配置不同的域名和网站根目录之间的映射关系。
HTTP/2
- 所有数据以二进制传输
- 多工。双向的、实时的通信,就叫做多工。举例来说,在一个TCP连接里面,服务器同时收到了A请求和B请求,于是先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。
- 头信息压缩以及服务器推送等提高效率的功能。
三次握手
进行三次握手的目的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小信息。三次握手由客户端发起,第一次握手, 客户端创建一个请求数据包,指明客户端打算连接服务器的端口,发送完毕进入SYN_SEND
状态;二次握手,服务器端发送确认包,进入SYN_RCVD
状态;三次握手,客户端再次发送确认包。发送完毕后,客户端进入ESTABILISHED
状态,服务器收到后也进入ESTABLISHED
状态。
二次握手后客户端和服务器端本来已经相互通信,交换信息了,本来可以直接建立连接了。但是为什么要进行三次握手呢?
这是服务器端为防止服务器端误会客户端的意思,服务器端开启无用连接,而浪费资源。
这就好比,一个你一直有好感的女孩向你发了个信息,“我喜欢你”。收到消息,你激动不已,你发了封信息“我也爱你,咱们交往吧”,然后就辗转反侧等消息,整夜没睡。但是第二天女孩说,不好意思,人家是玩的真心话大冒险。二次握手,不可靠。就是这个道理。如果有良知的美丽女孩当天就应该给人家回信进行第三次握手,拒绝或者接受。
URI、URL和URN的区别
URI(Uniform resource identifier) 统一资源标识符
URL(uniform resource locator) 统一资源定位器(网址)
URN(uniform resource name) 统一资源命名(ISBN 编码)
URL 是 URI,URN 也是 URI。URL 和 URN 两种兼备也是 URI。
URN定义某事物的身份,而URL提供查找该事物的方法。
用于标识唯一书目的ISBN系统是一个典型的URN使用范例。例如,ISBN 0-486-27557-4无二义性地标识出莎士比亚的戏剧《罗密欧与朱丽叶》的某一特定版本。为获得该资源并阅读该书,人们需要它的位置,也就是一个URL地址。在类Unix操作系统中,一个典型的URL地址可能是一个文件目录,例如file:///home/username/RomeoAndJuliet.pdf。该URL标识出存储于本地硬盘中的电子书文件。因此,URL和URN有着互补的作用。
HTTP 报文格式
请求报文:
1 | GET /index.txt HTTP/1.0 |
相应报文:
1 | HTTP/1.0 200 OK |
TIP:其中
GET
、POST
等命令是语义化的定义,GET
请求一个数据,POST
创建一个数据,但是他们都只是协议上规定的,不是强约束的,可以手动修改其行为,有点像HTML5标签。
HTTP 状态码
响应分为五类:
100-199 服务器收到请求
200-299 成功响应
300-399 重定向
400-499 客户端错误
500-599 服务器错误
常见的状态码:
200 请求成功
301 永久重定向(浏览器会记住返回301的网址,下次直接访问另一个网址)
302 临时重定向(下次再访问旧网址,还是要先访问旧网址,再根据 location 访问新网址)
304 资源未被修改
403 没有权限
404 资源未找到
500 服务器遇到了不知道如何处理的问题
504 网关超时
跨域
同源政策:协议、域名、端口号都相同则同源。如果不同源有如下限制:
- 当前域下的 JS 脚本不能访问其他作用域的 cookie、localStorage 和 indexDB。
- 当前域下的 JS 脚本不能操作访问其他域下的 DOM。
- 当前域下的 ajax 无法发送跨域请求。
通过 http://127.0.0.1:8888
获取到文件index.html
,如果文件中有一段js脚本,请求http://127.0.0.1:8887
的数据,也就是不同源的数据,浏览器会向8887服务器发送请求,并且接收返回内容,但是会检查是否有Access-Control-Allow-Origin
头,并且设置为允许,就会将响应内容忽略掉,并返回错误。
解决办法:
- CORS。8887的服务端响应时可以添加
"Access-Control-Allow-Origin":"http://127.0.0.1:8888"
消息头,允许跨域请求。通过Access-Control-Allow-Headers:"*"
允许跨域请求时添加的某些请求头。 - JSONP。浏览器允许
<link>
、<img>
、<script>
在标签上写 URL 加载内容允许跨域。JSONP 就是在<script>
上加载一个链接,向服务器请求JSON数据,服务器收到请求后,将数据放在一个指定名字的回调函数里传回来,客户端修改返回的内容。 - WebSocket。该协议不实行同源政策,只要服务器支持,就可以实现跨域。
- window.postMessage。HTML5的跨文档通信API,允许跨窗口通信,不论这两个窗口是否同源。
- 一级域名相同的域名,可以通过设置
document.domain="example.com"
来共享Cookie。
以上办法解决的跨域限制是不同的,例如:CORS、JSONP和WebSocket解决了AJAX跨域的问题。而document.domain
解决了Cookie跨域的问题,window.postMessage
解决了DOM跨域的问题。DOM跨域,典型的例子是iframe
窗口和window.open
方法打开的窗口,它们与父窗口无法通信。
HTTP 缓存
Cache-Control 头
HTTP/1.1 定义的Cache-Control
头用来区分对缓存机制的支持情况,请求头和响应头都支持这个属性。通过它提供的不同值来定义缓存策略。*
表示浏览器端常用的。
1 | // *缓存中不得存储任何关于客户端和服务端响应的内容。 |
缓存验证
Expire
Expire 是 HttpHeader 中代表资源的过期时间,由服务器端设置。如果带有 Expire ,则在 Expire 过期前不会发生 Http 请求,直接从缓存中读取。用户强制刷新例外(Windows:ctrl+F5
,Mac:command+option+R
),强制刷新是指无论如何都从服务器重新获取数据。
Last-Modified
Last-Modified 是 HttpHeader 中的资源的上次修改时间,如果带有 Last-Modified ,下一次发送 Http 请求时,将会发生带 If-modified-since 的 HttpHeader。与服务器端进行对比,如果没有过期,将会收到 304 的响应,从缓存中读取。
Etag
Etag 是 HttpHeader 中代表资源的标签,在服务器端生成。如果带有 Etag ,下一次发送带 Etag 的请求,如果 Etag 没有变化将收到 304 的响应,从缓存中读取。
Etag 在使用时要注意相同资源多台 Web 服务器的 Etag 的一致性。所以分布式环境(比如CDN)很少使用ETag。
区别:
Expire 兼容 HTTP/1.0 浏览器。
Etag 更加严格的验证,可以可靠的比较指纹。
Last-Modified 不验证实际页面内容是否更改,对页面频繁更改的网页更加有利。
Cookie 和 Session
Cookie 在服务端返回数据的时候通过Set-Cookie
设置,浏览器获取Cookie后保存在本地,下次请求会自动带上,Cookie 是键值对,可以设置多个。max-age
和expires
设置过期时间,HttpOnly无法通过document.cookie
访问。Session与之类似。
不过Session与Cookie不同之处在于,Cookie把数据放在客户端,而Session把数据放在服务器端。
将登陆信息等重要信息存放为Session,其他信息放在Cookie中。
Cookie, LocalStorage 与 SessionStorage 的区别:
长连接和短连接
TCP 本身并没有长短连接的区别,长短与否,完全取决于我们怎么用它。
- 短连接:每次通信时,创建 Socket;一次通信结束,调用 socket.close()。这就是一般意义上的短连接,短连接的好处是管理起来比较简单,存在的连接都是可用的连接,不需要额外的控制手段。
- 长连接:每次通信完毕后,不会关闭连接,这样可以做到连接的复用。长连接的好处是省去了创建连接的耗时。
短连接和长连接的优势,分别是对方的劣势。想要图简单,不追求高性能,使用短连接合适,这样我们就不需要操心连接状态的管理;想要追求性能,使用长连接,我们就需要担心各种问题:比如 端对端连接的维护,连接的保活。
HTTP1.1规定了默认保持长连接(HTTP persistent connection ,也有翻译为持久连接),数据传输完成了保持TCP连接不断开(不发RST包、不四次握手),等待在同域名下继续用这个通道传输数据;相反的就是短连接。
参考文献
- HTTP协议原理+实践 Web开发工程师必学-慕课网实战
- 详解 四层、五层、七层 计算机网络模型 - 掘金
- 应用层 - 维基百科,自由的百科全书
- 网络层 - 维基百科,自由的百科全书
- 数据链路层 - 维基百科,自由的百科全书
- 物理层 - 维基百科,自由的百科全书
- HTTP 协议入门 - 阮一峰的网络日志
- 同一个ip通一个80端口部署多个网站的原理-虚拟主机技术本质解析_walkingmanc的专栏-CSDN博客
- TCP为什么需要3次握手与4次挥手_zhanghongzheng3213的专栏-CSDN博客
- 统一资源标志符 - 维基百科,自由的百科全书
- Front-End-Interview-Notebook/JavaScript.md at master · CavsZhouyou/Front-End-Interview-Notebook
- 浏览器同源政策及其规避方法 - 阮一峰的网络日志
- HTTP 缓存 - HTTP | MDN
- 【技术心得】Last-Modified,Etag,Expire区别 - coolfiry - ITeye博客
- 详说 Cookie, LocalStorage 与 SessionStorage | 咀嚼之味
- Tcp长连接和keepalive - 简书
- HTTP协议中的长连接和短连接(keep-alive状态) - duanxz - 博客园