内容没有特殊表明或链接。均来自文底资料。若需更细了解。可自行寻找。
http 响应码
参考http错误码原理及复现 - 499,500,502,504
各种状态码【PHP面试题】HTTP/1.1中,状态码 200 301 304 403 404 500 的含义。
301 跟 302的区别?
301用于废弃原地址跳转新地址。
302用于暂时无法访问原地址跳转新地址,两者都需要浏览器重新发起一次请求。
性能对比:对于单次请求来说是没什么差别的,但浏览器会对301做优化,后续的请求就不会再有跳转动作,所以会快一些。
http是怎么进行内容协商的?
客户端用 Accept 头告诉服务器希望接收什么样的数据,而服务器用 Content 头告诉客户端实际发送了什么样的数据。
Accept 字段标记的是客户端可理解的 MIME type。服务器会在响应报文里用头字段 Content-Type 告诉实体数据的真实类型。
协商 可用参数q指定优先级。如下:
Accept: text/html,application/xml;q=0.9,*/*;q=0.8
服务器收到请求头后,就会计算权重,再根据自己的实际情况优先输出 HTML 或者 XML。
此图来自《透视HTTP协议》服务器端向浏览器发送数据,Content-Length的值小于包体长度会是怎么样?若大于呢?
Content-Length若小,浏览器解析,只会解析Content-Length长度。剩余的不解析。但服务器是会往全的发,可用wireshark抓包看。
若大,浏览器显示“该网页无法正常运作”。http状态码是200。response无法解析(Failed to load response data)。wireshark是能看到body体的。
两种传输方式是?
1.定长包体的方式。
Content-Length 头部明确指明包体长度。
优点:
- 接收端处理更简单。
2.不定长包体的chunk传输方式。
Transfer-Encoding头部指明使用Chunk传输方式。Content-Length 头部应被忽略。
优点:
- 基于长连接持续推送动态内容。
- 压缩体积较大的包体,不必完全压缩完(计算出头部)在发送,可边发送边压缩。
- 传递必须在包体传输完才能计算出的Trailer 头部。
内容大了,如何处理呢?
1.压缩。比如,开启gzip压缩。
2.分块传输。在响应报文里用头字段“Transfer-Encoding: chunked”来表示。
3.范围请求。允许客户端在请求头里使用专用字段来表示只获取文件的一部分。该方式可用于断点续传跟多线程下载。
4.多段数据。 范围请求一次只获取一个片段,其实它还支持在 Range 头里使用多个“x-y”,一次性获取多个片段数据。
断点续传跟多线程下载的简单步骤
- 先发个 HEAD,看服务器是否支持范围请求,同时获取文件的大小;
- 开 N 个线程,每个线程使用 Range 字段划分出各自负责下载的片段,发请求传输数据;
短链接与长连接(keep-alive)讲下?
1.短链接
客户端与服务器的整个连接过程很短暂,不会与服务器保持长时间的连接状态。
缺点是:每次发手包都要建立连接。增加了rtt(往返)时间,限制了服务器处理更多的请求。
2.长连接(keep-alive)
解决短链接的问题,“成本均摊”,既然 TCP 的连接和关闭非常耗时间,那么就把这个时间成本由原来的一个“请求 - 应答”均摊到多个“请求 - 应答”上。
http1.1连接都会默认启用长连接。若客户端需要服务器端用长连接,在请求头加Connection: keep-alive
,若服务端也支持长连接,响应头也会加Connection: keep-alive
。
keep-alive (长连接)虽好,但有什么副作用呢?
TCP长时间不关闭,会消耗服务器资源。怎么去规避呢?
1.客户端可在请求头加“Connection: close”,告知服务器关闭。
2.以nginx为例子,可keepalive_timeout指定超时时间。keepalive_requests指定最大请求数。
什么是队头阻塞?如何处理?
队头阻塞
因为 HTTP 规定报文必须是“一发一收”,这就形成了一个先进先出的“串行”队列。队列里的请求没有轻重缓急的优先级,只有入队的先后顺序,排在最前面的请求被最优先处理。
如果队首的请求因为处理的太慢耽误了时间,那么队列里后面的所有请求也不得不跟着一起等待,结果就是其他的请求承担了不应有的时间成本。
优化方式
“并发连接”,同时对一个域名发起多个长连接,用数量来解决质量的问题。缺点,连接不宜过多。索性,浏览器都有自己限制。
怎么加强Cookie的安全性呢?
在 JS 脚本里可以用 document.cookie 来读写 Cookie 数据,这就带来了安全隐患,有可能会导致“跨站脚本”(XSS)攻击窃取数据。
属性“HttpOnly” :告诉浏览器,此 Cookie 只能通过浏览器 HTTP 协议传输,禁止其他方式访问,浏览器的 JS 引擎就会禁用 document.cookie 等一切相关的 API,脚本攻击也就无从谈起了。
属性“SameSite” :”可以防范“跨站请求伪造”(XSRF)攻击,设置成“SameSite=Strict”可以严格限定 Cookie 不能随着跳转链接跨站发送,而“SameSite=Lax”则略宽松一点,允许 GET/HEAD 等安全方法,但禁止 POST 跨站发送。
属性“Secure”:表示这个 Cookie 仅能用 HTTPS 协议加密传输,明文的 HTTP 协议会禁止发送。但 Cookie 本身不是加密的,浏览器里还是以明文的形式存在。
缓存控制
“Cache-Control”字段里的“max-age”,(又叫“新鲜度”“缓存寿命”,类似 TTL,Time-To-Live),时间的计算起点是响应报文的创建时刻(即 Date 字段,也就是离开服务器的时刻),而不是客户端收到报文的时刻,也就是说包含了在链路传输过程中所有节点所停留的时间。
Ctrl+F5的强刷,你认为做了哪些事情呢?
它其实是发了一个“Cache-Control: no-cache”,含义和“max-age=0”基本一样,就看后台的服务器怎么理解,通常两者的效果是相同的。
条件请求流程是什么?
ETag 是“实体标签”(Entity Tag)的缩写,是资源的一个唯一标识,主要是用来解决修改时间无法准确区分文件变化的问题。
图来自《透视HTTP协议》获取客户端用户真实ip的方式有哪些?
“X-Forwarded-For”的字面意思是“为谁而转发”,“X-Forwarded-For”追加的是请求方的 IP 地址。所以,在字段里最左边的 IP 地址就客户端的地址。(有代理的情况下会追加)
“X-Real-IP”是另一种获取客户端真实 IP 的手段,它的作用很简单,就是记录客户端 IP 地址,没有中间的代理信息,相当于是“X-Forwarded-For”的简化版。如果客户端和源服务器之间只有一个代理,那么这两个字段的值就是相同的。
http 跟https
此图来自《透视HTTP协议》TLS 由记录协议、握手协议、警告协议、变更密码规范协议、扩展协议等几个子协议组成,综合使用了对称加密、非对称加密、身份认证等许多密码学前沿技术。
握手时使用 ECDHE 算法进行密钥交换,用 RSA 签名和身份认证,握手后的通信使用 AES 对称算法,密钥长度 256 位,分组模式是 GCM,摘要算法 SHA384 用于消息认证和产生随机数。
https 慢的优化方式
硬件优化
- 更快的 CPU,最好还内建 AES 优化,这样即可以加速握手,也可以加速传输。
- “SSL 加速卡”,加解密时调用它的 API,让专门的硬件来做非对称加解密,分担 CPU 的计算压力。
- “SSL 加速服务器”,用专门的服务器集群来彻底“卸载”TLS 握手时的加密解密计算,性能自然要比单纯的“加速卡”要强大的多。椭圆曲线也要选择高性能的曲线,最好是 x25519,次优选择是 P-256。对称加密算法方面,也可以选用“AES_128_GCM”,它能比“AES_256_GCM”略快一点点。
- 证书优化:证书传输,一个是证书验证。
- 会话复用
软件优化
- 软件升级:比如把 Linux 内核由 2.x 升级到 4.x,把 Nginx 由 1.6 升级到 1.16,把 OpenSSL 由 1.0.1 升级到 1.1.0/1.1.1。
- 协议升级:应当尽量采用 TLS1.3,它大幅度简化了握手的过程,完全握手只要 1-RTT,而且更加安全。
IP协议与TCP协议区别?
IP 是一种无连接、不可靠的协议:它尽最大可能将数据报从发送者传输给接收者,但并不保证包到达的顺序会与它们被传输的顺序一致,也不保证包是否重复,甚至都不保证包是否会达到接收者。
TCP 是一个可靠的(reliable)、面向连接的(connection-oriented)、基于字节流(byte-stream)、全双工的(full-duplex)协议。
图来自《深入理解 TCP 协议:从原理到实战》TCP 如何保证它的可靠性的呢?
TCP 要想在IP基础上构建可靠的传输层协议,必须有一个复杂的机制来保障可靠性。主要有以下面几个方面:
- 对每个包提供校验和
- 包的序列号解决了接收数据的乱序、重复问题
- 超时重传
- 流量控制、拥塞控制
报文的大小取决于哪几个方面?
路径最大传输单元 MTU、发送窗口大小、拥塞窗口大小等。
三次握手
截图自《nginx核心知识100讲》下面是具体的过程:
1.客户端的协议栈向服务器端发送了 SYN 包,并告诉服务器端当前发送序列号 j,客户端进入 SYNC_SENT 状态;
2.服务器端的协议栈收到这个包之后,和客户端进行 ACK 应答,应答的值为 j+1,表示对 SYN 包 j 的确认,同时服务器也发送一个 SYN 包,告诉客户端当前我的发送序列号为 k,服务器端进入 SYNC_RCVD 状态;
3.客户端协议栈收到 ACK 之后,使得应用程序从 connect 调用返回,表示客户端到服务器端的单向连接建立成功,客户端的状态为 ESTABLISHED,同时客户端协议栈也会对服务器端的 SYN 包进行应答,应答数据为 k+1;
4.应答包到达服务器端后,服务器端协议栈使得 accept 阻塞调用返回,这个时候服务器端到客户端的单向连接也建立成功,服务器端也进入 ESTABLISHED 状态。
为什么三次握手?
为什么tcp建⽴连接需要三次握⼿,解释如下
tcp连接的双⽅要确保各⾃的收发消息的能⼒都是正常的。
客户端第⼀次发送握⼿消息到服务端,
服务端接收到握⼿消息后把ack和⾃⼰的syn⼀同发送给客户端,这是第⼆次握⼿,
当客户端接收到服务端发送来的第⼆次握⼿消息后,客户端可以确认“服务端的收发能⼒OK,客户端的收发能⼒OK”,但是服务端只能确认“客户端的发送OK,服务端的接收OK”,所以还需要第三次握⼿,客户端收到服务端的第⼆次握⼿消息后,发起第三次握⼿消息,服务端收到客户端发送的第三次握⼿消息后,就能够确定“服务端的发送OK,客户端的接收OK”,⾄此,客户端和服务端都能够确认⾃⼰和对⽅的收发能⼒OK,tcp连接建⽴完成。
能不能改成两次?
A 和 B 原来建立了连接,做了简单通信后,结束了连接。A 建立连接的时候,请求包重复发了几次,有的请求包绕了一大圈又回来了,B 会认为这也是一个正常的的请求的话,因此建立了连接,可以想象,这个连接不会进行下去,也没有个终结的时候,纯属单相思了。因而两次握手肯定不行。(更多的理解参考《趣谈网络协议》)
四次挥手
来自《深入理解 TCP 协议:从原理到实战 》普通文件跟 socket 文件的区别?
对于普通⽂件描述符⽽⾔,⼀个⽂件描述符代表了打开的⼀个⽂件句柄,通过调⽤ write 函数,操作系统内核帮我们不断地往⽂件系统中写⼊字节流。注意,写⼊的字节流⼤⼩通常和输⼊参数 size 的值是相同的,否则表示出错。
对于套接字描述符⽽⾔,它代表了⼀个双向连接,在套接字描述符上调⽤ write 写⼊的字节数有可能⽐请求的数量少,这在普通⽂件描述符情况下是不正常的。
阻塞式套接字最终发送返回的实际写⼊字节数和请求字节数是相
等的。
UDP 和 TCP 之间最⼤的区别?
TCP 是⼀个⾯向连接的协议,TCP 在 IP 报⽂的基础上,增加了诸如重传、确认、有序传输、拥塞控制等能⼒,通信的双⽅是在⼀个确定的上下⽂中⼯作的。
⽽ UDP 则不同,UDP 没有这样⼀个确定的上下⽂,它是⼀个不可靠的通信协议,没有重传和确认,没有有序控制,也没有拥塞控制。我们可以简单地理解为,在 IP 报⽂的基础上,UDP 增加的能⼒有限。
UDP 不保证报⽂的有效传递,不保证报⽂的有序,也就是说使⽤ UDP 的时候,我们需要做好丢包、重传、报⽂组装等⼯作。
什么是本地套接字?
本地套接字是⼀种特殊类型的套接字,和 TCP/UDP 套接字不同。TCP/UDP 即使在本地地址通信,也要⾛系统⽹络协议栈,⽽本地套接字,严格意义上说提供了⼀种单主机跨进程间调⽤的⼿段,减少了协议栈实现的复杂度,效率⽐ TCP/UDP 套接字都要⾼许多。类似的IPC 机制还有 UNIX 管道、共享内存和 RPC 调⽤等。
TIME_WAIT 是如何产生的?
TCP 连接对外提供服务。每个连接会占⽤⼀个本地端⼝,当在⾼并发的情况下,TIME_WAIT 状态的连接过多,多到把本机可⽤的端⼝耗尽,应⽤服务对外表现的症状,就是不能正常⼯作了。
当过了⼀段时间之后,处于 TIME_WAIT 的连接被系统回收并关闭后,释放出本地端⼝可供使⽤,应⽤服务对外表现为,可以正常⼯作。这样周⽽复始,便会出现了⼀会⼉不可以,过⼀两分钟⼜可以正常⼯作的现象。
那么为什么会产⽣这么多的 TIME_WAIT 连接呢?
四次挥手, 只有发起连接终⽌的⼀⽅会进⼊ TIME_WAIT 状态。
在 TIME_WAIT 停留持续时间是固定的,是最⻓分节⽣命期 MSL(maximum
segment lifetime)的两倍,⼀般称之为 2MSL。和⼤多数 BSD 派⽣的系统⼀样,Linux系统⾥有⼀个硬编码的字段,名称为TCP_TIMEWAIT_LEN,其值为 60 秒。也就是说,Linux 系统停留在 TIME_WAIT 的时间为固定的 60 秒。
TIME_WAIT 的作⽤是什么?
第一个原因是:数据报文可能在发送途中延迟但最终会到达,因此要等老的“迷路”的重复报文段在网络中过期失效,这样可以避免用相同源端口和目标端口创建新连接时收到旧连接姗姗来迟的数据包,造成数据错乱。
第二个原因是确保可靠实现 TCP 全双工终止连接。关闭连接的四次挥手中,最终的 ACK 由主动关闭方发出,如果这个 ACK 丢失,对端(被动关闭方)将重发 FIN,如果主动关闭方不维持 TIME_WAIT 直接进入 CLOSED 状态,则无法重传 ACK,被动关闭方因此不能及时可靠释放。
为什么时间是两个 MSL?
- 1 个 MSL 确保四次挥手中主动关闭方最后的 ACK 报文最终能达到对端
- 1 个 MSL 确保对端没有收到 ACK 重传的 FIN 报文可以到达
2MS = 去向 ACK 消息最大存活时间(MSL) + 来向 FIN 消息的最大存活时间(MSL)
TIME_WAIT 的危害有哪些?
第⼀是内存资源占⽤,这个⽬前看来不是太严重,基本可以忽略。
第⼆是对端⼝资源的占⽤,⼀个 TCP 连接⾄少消耗⼀个本地端⼝。要知道,端⼝资源也是有限的,⼀般可以开启的端⼝为 32768~61000 ,也可以通过net.ipv4.ip_local_port_range指定,如果TIME_WAIT 状态过多,会导致⽆法创建
新连接。
如何优化TIME_WAIT?
截图自《nginx核心知识100讲》 截图自《nginx核心知识100讲》修改文件vim /etc/sysctl.conf
。
内容来源
- 《Nginx核心知识100讲》课件地址
- 《透视http协议》
- 《网络编程实战》
- 《趣谈网络协议》
- 《Web协议详解与抓包实战》
- 《深入理解TCP协议:从原理到实战》
网友评论