《面试官不讲武德》对 Java 初级程序猿死命摩擦 Http 协议
前言
我被 Hr 领进了一个小黑屋,让我在这里等面试官,过来一会,一位穿着拖鞋的中年男子走了进来,看着他绝顶聪明的发际线,知道这肯定是位大佬,我心里倍感到了压力;
面试官果然不是盖的,刚坐下后就开始立即暴力输出了
面试官:我看你简历上写了熟悉 Http 协议,当我们使用浏览器访问网址: `https://silently9527.cn`会发生什么?
我:(这尼玛就是怕被搞事情所以没写精通,这也被搞。会发生什么,当然是展示出网页啊,大脑飞速旋转,脖子快断的时候,终于想到面试官可能想要问什么了)
我:英俊潇洒的面试官,你好!
首先浏览器会去访问 DNS 服务器,查询到域名对应的 ip 地址是多少,然后浏览器再去访问这个 ip 地址;如果还要往底层在说的话,就会涉及到 tcp/ip 的分层,我还是来画张图吧。
服务器返回资源的过程也是类似的方式
面试官:你刚才有谈到 tcp/ip 的分层,能详细说下吗?
我:(还好前前大学女友没把我当年上课的笔记给扔掉,刚好昨晚找回来温习了一下,温故而知新!只是笔记而已,大家别想歪了!)
插图
我:TCP/IP 协议族分为 4 层:应用层、传输层、网络层、数据链路层
应用层:主要是与应用通信使用到的协议,比如:FTP、DNS、HTTP
传输层:为应用层提供在两台机器之间数据传输,有两种协议:TCP、UDP
网络层:两台机器之间在传输的过程中会经过多个路由器有多条路线,网络层主要是从中选择一条路线
数据链路层:用来处理连接网络的硬件部分,比如说网卡、设备驱动等
面试官:在 tcp/ip 的分层里面,当客户端发起 http 请求到达服务端的过程中,数据包的封装以及解包的过程是怎样的?
我:在这个分层中,每次网络请求都会按照分层的顺序与对方进行通信,发送端从应用层往下走,接收端从数据链路层往上走;以 Http 来举例的话:
客户端在应用层(Http 协议)发起一个 HTTP 请求
在传输层(TCP 协议)把从应用层收到的 Http 请求数据包分隔成小的数据包,并打好序
网络层(IP 协议)收到数据包后选择发送路径
服务器收到数据后按照顺序往上发送,直到应用层收到数据
在发送方每经过一层,就会被加上该层的首部信息,当接收方接受到数据后,在每一个层会去掉对应的首部信息
面试官:TCP 如何保证数据可靠到达目的地?
我:TCP 协议采用的三次握手策略
第一次握手:建立连接时,客户端发送 syn 包(syn=j)到服务器,并进入 SYN_SEND 状态,等待服务器确认;
第二次握手:服务器收到 syn 包,必须确认客户的 SYN(ack=j+1),同时自己也发送一个 SYN 包(syn=k),即 SYN+ACK 包,此时服务器进入 SYN_RECV 状态;
第三次握手:客户端收到服务器的 SYN+ACK 包,向服务器发送确认包 ACK(ack=k+1),此包发送完毕,客户端和服务器进入 ESTABLISHED 状态,完成三次握手。
面试官:为什么是三次握手,而不是两次或者 4 次呢?
我:假如说是两次握手,如果客户端自己处理异常或者是服务器返回的 ack 消息丢失,那么客服端会认为连接建立失败,再次重新发送请求建立连接,但是服务端却无感知,以为连接以及正常建立,导致服务器建立无用的连接,浪费资源
假如四次握手,如果三次已经足够,那就不需要四次了。如果四次的话,最后一个 ACK 丢失,那么又会出现两次握手的问题。
面试官:竟然都到说了三次握手,那就说说四次挥手吧?
我:
客户端向服务器发送 FIN 希望断开连接请求。
服务器向客户端发送 ACK,表示同意释放连接。
服务器向客户端发送一个 FIN 表示希望断开连接。
客户端向服务器返回一个 ACK 表示同意释放连接。
面试官:为什么断开连接需要四次而不是三次呢?
我:因为当服务器收到客户端断开连接的请求后,服务器不能立即断开连接,因为可能服务器端还有数据未发送完成,所以只能回复一个 ACK 表示我已收到消息;等服务器端数据发送完成之后再发送一个 FIN 希望端开连接的消息,客户端回复 ACK 之后,就可以安全断开了
面试官:为什么说 Http 协议无状态协议?怎么解决 Http 协议无状态?
我:本身 HTTP 协议是不保存状态的,自身不对请求和响应直接的通信状态进行保存,所以是无状态的协议。因为在有些场景下我们需要保存用户的登录信息,所以引入了 cookie 来管理状态。客户端第一次请求服务器的时候,服务器会生成 cookie 添加在响应头里面,以后客户端的每次请求都会带上这个 cookie 信息。
面试官:Cookie 与 Session 有什么区别?
我:
Cookie 是有服务器生成,写入到请求的响应头中,浏览器会保存;服务器通过
Set-Cookie
字段向客户端设置 Cookie,属性:
Name=value 设置 cookie 的名字和值
expires 设置 Cookie 的有效期
domain=域名 表示只能在哪个域名下生效
secure 表示只能在 Https 的通信时才发送 cookie
HttpOnly 表示不能被 javascript 访问
Session 也是服务器生成的,表示服务器中的一片内存,每个客服端对应一个 Session,客户端之间的 Session 相互独立;每次客户端发起请求,都会带上 Cookie,Cookie 里面一般都会有一个 JSESSIONID,服务器就是通过这个 JESSIONID 来找到客户端对应 Session,所以一般用户的登录信息都会存放在 Session;这样也解决了 Http 协议无状态的问题
面试官:Http 协议中有那些请求方式?如何选择使用什么方法?
我:
GET : 获取资源; 所以查询操作一般用 GET
POST: 传输实体主体, 创建更新操作用 POST
PUT: 传输文件
HEAD: 获取报文首部,如果想要查询某个请求的头信息可以用这个方法
DELETE: 删除资源,所以删除操作用 DELETE
OPTIONS: 询问服务器支持哪些方法,响应头中返回 Allow: GET,POST,HEAD
TRACE: 追踪路径;在请求头中在 Max-Forwards 字段设置数字,每经过一个服务器该数字就减一,当到 0 的时候就直接返回,一般通过该方法检查请求发送出去是否被篡改
面试官:Http 如何实现持久连接的呢?
我:(毛线啊,我只是个来面试 Java 的初级程序员,干嘛要反复拿 Http 来摩擦我呢?!不过没事,我皮的很,这道题我又会)
我:在 HTTP 协议的早期,每进行一次 HTTP 通信就要断开一次 tcp 连接,当时传输的内容少还能接受,现在每个网页一般的会包含大量的图片,每次请求都会造成 TCP 连接的连接和断开,增加通信的开销。
为了解决这个问题所以想出了持久连接的方法,也叫做 keep-alive,只要一端没有提出断开连接就会一直保持 TCP 连接的状态。持久化连接使的客户端可以同时并发发送多个请求,不用一个接着一个的等待响应。
面试官:大文件的断点续传是如何实现的呢?
我:HTTP 请求头有个 Range 字段;我们下载文件的时候如果遇到网络中断,如果重头开始下载会浪费时间,所以我们可以从上一次中断处继续开始下载;具体的操作:
或者指定 5001 以后的所有数据
响应返回的状态码是 206
面试官:刚才你有提到状态码,那常见 Http 协议状态码有哪些?
我:(面试官我简历上忘记写了,我曾经是学霸,记忆力好,背书没输过)
我:HTTP 的状态码主要分为了四类:
2xx: 成功状态码,表示请求正常处理完毕
3xx: 重定向状态码,表示需要附加操作才能完成成请求
4xx: 客户端错误状态码
5xx: 服务器错误状态码
常见的状态码有: 200(请求正常处理完成)、204(请求处理成功,但是没有资源返回)、206(表示客户端进行了范围请求,响应报文中包含了 Content-Range)、301(永久性重定向,请求的资源以及被分配到了新的地址)、302(临时重定向,希望用户并且请求新地址)、400(客户端请求报文出现错误,通常是参数错误)、401(客户端未认证错误)、403(没有权限访问该资源)、404(未找到请求的资源)、405(不支持该请求方法,如果服务器支持 GET,客户端用 POST 请求就会出现这个错误码)、500(服务器异常)、503(服务器不能提供服务)
我:(这我都能记住,是不是的给我点个赞)(已疯狂暗示兄弟们点赞,不要白嫖哦)
面试官:HTTP 报文由哪些部分组成?
我:报文的类型分为了请求报文和响应报文两种;
请求报文包含三部分:
请求行:包含请求方法、URI、HTTP 版本信息
请求首部字段
请求内容实体
响应报文包含三部分:
状态行:包含 HTTP 版本、状态码、状态码的原因短语
响应首部字段
响应内容实体
面试官:Http 有哪些问题,什么是 https?
我:Http 的问题
通信使用明文不加密,内容可能被窃听
不验证通信方身份,可能遭到伪装
无法验证报文完整性,可能被篡改
HTTPS 就是 HTTP 加上 SSL 加密处理(一般是 SSL 安全通信线路)+认证+完整性保护
面试官:HTTPS 是如何保证数据安全的?
我:首先需要说到两种加密机制
对称加密:客户端和服务器都使用了同一个密钥加密,效率较高
非对称加密:分为了公开密钥和私有密钥,公开密钥可以在网络上传输,使用公开密钥加密后的内容只有私有密钥才能解密,效率较低
由于这两个加密的特别,HTTPS 采用的时候混合加密机制,在交换密钥的阶段使用的是非对称加密,在建立通信交换报文阶段采用的是对称加密
以访问 https://silently9527.cn 举例
浏览器向服务器发起请求,服务器在接收到请求之后,返回证书和密钥
浏览器向第三方证书机构验证证书是否合法,如果不合法浏览器将会弹出警告页面,让用户选择是否继续访问
如果证书合法浏览器生成随机串,使用公钥加密发送给服务器,服务器使用私钥解密出随机串,服务器使用随机串加密内容返回给客户端
之后客户端和服务器端都将通过随机串进行对称加密
面试官:为什么需要证书认证机构,不要 https 就不安全了吗?
我:虽然 https 是可以加密的,但是因为请求还是可以被拦截,如何让客户端知道返回给自己的公钥是真实服务器给的而不是攻击者给的;这就需要验证证书的合法性,所以需要引入第三方认证机构。通常 https 的证书需要到第三方机构去申请购买,如果是我们自己生成的 https 证书浏览器验证不过会弹出警告。
面试官:那浏览器是如何保证证书验证的过程是安全的呢?
我:浏览器在向证书认证中心验证证书的过程使用的也是非对称加密,这里想要让公钥能够安全的转交给客户端,是非常困难的,所以浏览器的开发商通常会在浏览器内部植入常用认证机构的公开密钥
面试官:http 相关的协议掌握的还可以,我们继续聊聊 Java.....
能撑到现在,你自己都忍不住自己给自己点个赞了!(再次暗示点赞)
写到最后(点关注,不迷路)
本篇面试故事纯属虚构,请大家不要当真,玩笑归玩笑,莫拿面试开玩笑。
文中或许会存在或多或少的不足、错误之处,有建议或者意见也非常欢迎大家在评论交流。
最后,白嫖不好,创作不易,希望朋友们可以点赞评论关注三连,因为这些就是我分享的全部动力来源🙏
原创不易 转载请注明出处:https://silently9527.cn/archives/68
参考:《图解 HTTP》
版权声明: 本文为 InfoQ 作者【Silently9527】的原创文章。
原文链接:【http://xie.infoq.cn/article/173234e88194f9f4d4ed77a03】。文章转载请联系作者。
评论