面试汇总第一篇

​ 面试重基础,数据库、操作系统、数据结构、计算机网络、语言基础,

​ 面试和平时工作不同,平时工作只需要知道知识点,会灵活运用就行,面试要求能表达出来,所以需要准备。

写在前面

我有幸读过蚂蚁金服的员工做出的计算机公司感悟,挑出好的地方记录:

职场感悟:

1:在阿里这种大厂,其实在很多公司也一样,沟通和反馈是非常非常重要,一味的埋头苦干的人其实是很吃亏的。我见过好几个踏实做事的同学被打上'325'走人的。所以一定要学会在老板和同事面前包装和表现自己。

2:需求太多、运维工作量太大,平时各种琐事会充满你所有的时间(甚至包括你的睡眠时间和周末时间),一定要学会解脱(思考解法或者寻求帮助再或者甩给别人),然后自己抽身去做些有成长有意思的事情,只有这样你才有时间去搞些容易拿KPI的项目,不然到时候你剩下的只有抱怨为什么这么忙,为什么脏话累活都是你干。实际上这些抱怨一点用都没有,在老板和大多数人眼里,只能说明你什么事都搞不定。以结果为导向的价值观里,过程是不重要的!

3:一般人的工作目的无非是为了在同等的条件下,获取更高的物质回报。如果你确实努力了也拼命了,还是得不到老板的精神认可,获取不到自己想要的物质回报,你要么改变自己,要么就改变环境-或者换个环境。

4:工作是公司的,只有技术、成长还有健康是自己的。此处不留爷,自有留爷处,但是打铁还需自身硬,说白了,你想跳槽也是要看你实力,在日常工作中一定要抽时间多学习多总结,互联网这行业,技术更新换代速度太快,只有自己成长才是王道。

面试经验:

我面的岗位都java 开发,前前后后面了很多一二线互联网公司,其中包括腾讯,阿里,滴滴,网易,美团、头条、快手等等,下面的文章水分较少,都是一些面试干货。希望能为大家圈一些“考试范围”,给大家面试带来一点点帮助。

第一个我要说的就是面试时间点很关键,这直接决定了你的竞争力和拿到offer的难度。同一个岗位,不同时间点面试,难度和要求是不一样的。因为这里要看缺人的程度和岗位HC的数量 根据我的观察在杭州互联网的话,一般每年年底机会比较多。另外就是如果有认识的人,推荐的比较急的或者“放水”几率比较大的岗位的话,那么你拿到offer的可能性自然而然就比较高,这就是我前面说的面试是实力的基础上加一点运气。

第二个点,java基础。我是毕业4年半,即将5年,面的岗位有开发工程师,有开发专家(近期也拿到过一二线厂的开发专家的offer)。基本每次面试都要准备一下java面试常见的“八股文”,也基本每次都会被问到,比如锁、spring、比如jvm 垃圾回收,比如hashmap等等,这些基础的肯定要掌握,甚至要滚瓜烂熟,举一反三。这里有一些大牛总结的面试必背题(包含答案),大家面试前可以看看,里面全是干活,这里划重点了blog.csdn.net/u014664750/…

另外,可以看下我CSDN的其他博客( 不行就改名),里面的文章大多数是面试常问到的一些基础的东西。

第三点:笔试题,最近两年的面试一些大厂基本都要做一些笔试题,一般都是牛客网上面出题,这些题大多数都是一些算法题,基本都是leetcood的原题,所以要准备面试的同学,要提前适应一下,去leetcood上面刷刷题。一般面试官会根据你的面试表现然后出一些不同难度的题目,如果你面试问题回答的比较好,给的题目就相对比较简单,如果回答的不好,可能就直接给你一道hard。

不过根据我的经验,大多数情况给的题都是leetcood上面热题100的中等难度的原题。我这里整理了一些我最近两个月面试过程中遇到的笔试原题,供大家参考:blog.csdn.net/ym123456677…

第四点,各种常用的中间件原理、源码:一些常用的框架比如rpc、任务调度、缓存-redis、MQ等等,特别是你项目中运用到的一些中间件,一定要掌握他的原理,如果有时间最好撸一下核心源码,一般的面试官很喜欢问这些东西,特别是小厂跳大厂的时候。这些知识点大家可以根据网上的文章和自己的情况去做一些相应的准备。 这里东西太多,我就不做总结了。

第五点,项目。说项目的时候如果是业务项目,就要体现出项目的难点和解法,最好有高并发、大数据量,怎么保证稳定性等等。如果是框架型的项目,就要体现出他的平台性、怎么保证高可靠等等。然后就是你在项目中做的哪些比较有特色的事,最难的事情(这个时候就是要活学活用了,不管是不是你做的,你只要能说的上来就是你的)。

这里可能有很多同学没接触到什么有难度的项目,就是项目在面试官眼中是没什么挑战性的,那这个时候你最好要准备一个中间件类似的项目说一下,来吸引一下面试官的眼球,比如限流、比如任务调度、比如配置平台等等,这些都是通用的万能的项目,很容易集成到自己的业务项目中。我这里给大家推荐一个许雪里老师的文章,上面的项目可以挑几个下载下来看几遍,然后合理的应用到面试过程中,项目地址www.xuxueli.com/page/projec… 或者 github.com/xuxueli

第六点,场景题。一般面试官会出一些场景题,让你给一些解决方案。遇到比较多的就是秒杀场景,或者其他的并发相关的场景。这个没有标准答案,就是看你的知识面了,能自圆其说就ok。回答的时候尽量考虑全面一些,多围绕下面几个点展开:容量规划、架构设计、缓存、数据迁移、同步方案、分库分表、高并发解决方案、数据一致性、幂等、甚至考虑一下回滚、性能压测、监控报警方案等,尽量全面一点,把你的知识面铺开

https://juejin.cn/post/6914581750111076359

自我感悟

我在工作了半年左右之后,在一次面试(编程猫)失败之后,个人又总结了一些想法:

1.要多面试、同时适当把握面试节奏。

因为我是转行过来的,学习过程中也基本上90%以上的内容都是通过搜索引擎自己获取的,经验很少,因此面试就成为我不可多得的宝贵的学习机会。尤其是面试技术岗这种东西,说起来大家都会说,但是了解和熟悉完全不是一回事,就像上学的时候学数学,你看课本永远是那些概念,只有在实际的应用场景中,技术才会变得活灵活现,也因此有了价值。如果你也和我一样,经验不多,同时身边又没有非常强的可以接触到很多时间的,不知道学什么,学了什么才能把所学的东西价值最大化,那就努力面试。

我记得我在面试的时候,js、es6的基础不足,我就找js、es6的教程,越详细越好(阮一峰);

html、css不会,就恶补html、css;

前端会被问到很多基础的网络、数据结构、操作系统的知识也自己去补,不能说全部手到擒来,基本上要有个印象;

2个月后我再出去面试,js会了但是webpack、gulp被问到不会,就回去恶补webpack、gulp;

算法题不行就去刷leetcode;

对node有要求但是自己不会就去补node;

与公司具体业务相关的,如前端涉及到的webgl、数据可视化等等也是因公司而异,有需要就去补,

前端框架的高级用法,比如eventbus、设计模式、高级组件、柯里化函数,问到不会就去看。

同时我自己也会努力发现我的不足,如typescript、react,自己看完了心里有个数再出去面试。

大概过了半年左右,我基本上已经掌握前端所需的大部分基础,颇有成就感。

2.要自己主动补,主动学习,自我驱动很重要

以我的经验看来,很多3年甚至5年经验的但是你感觉没有很高水平的,大部分是缺乏自我驱动的意识。在我刚开始的半年,我平常都会加班到8点半,如果公司有事我就做一做公司的事情,但是通常情况是如果事情不急的话我就会看自己的东西,正好我那段时间在学日语,很想考一个n2的证书,所以除了每周六会到公司加班,周末我还会找一个当时很火的自习室去看电脑或者刷日语,通常学习时间伟3-6个小时(包括中途打游戏划水)。

另外,我会把所有我看过的感觉比较好的有用的教程通通保存,我当时所有不管是台式还是笔记本,浏览器的网页都是好几个月都不关,就是为了防止自己错过。如果在微信上看到就会直接保存到微信上,然后会一直记着发给pc端。

同样的,当时我们公司的后端,有的3-5年的后端,只会java,问到go、python甚至kotlin,都说没有听过;我当时还看到一些很棒的go的教程或者python的教程推荐给他们,他们有的说会看看,其实我感觉并没有看,因为并没有什么反馈,他们好像对自己的现状很安逸。更糟的有人连基本的逻辑都不行,改一些简单的bug连基本的该改哪里都找不到,这样的人实在是差。他的差不在于编程差,而是他自己编程差还非要找一份编程的工作,不明白自己的长处,相当于当众揭自己短,实在难堪。别人与他共事也是极累。

对于前端也是一样,有的5年经验的,html、css、vue写的很熟,但是一问到eventbus、设计模式或者node这种深一点的问题就无所适从,对他们来说能找到基于现有的技术可以替代的方案比学一个新东西更具有吸引性,即使这个新东西可能有很多优点。同样的,我的同事一直想学node但就是不开始,我不知道是谁不让她学,我教会她翻墙的技巧,她都不记,下次翻墙依然不会,在我看来这样对于程序员来说很吃亏的,然后她自己似乎都无所谓,我绝对不能忍受自己是这个样子。

3.除了有意识,还要自律,说到做到

当时我们公司的很多人,连基本的9点上班都要调休,以至于老板每次早上到公司脸色都很难看,在多次强调早上按时上班之后最后不得已取消了上午调休制度。并不是说不可以调休,但是日常起床都要调休推迟,那么可想而知在没有约束的日子里更是不可能早起的,而我基本上周日也最迟10点多起床,如果计划早点就直接出门,如果计划是在下午就10点多出门吃饭,然后回去休息一会出门。这样保持了半年,收获也很多。

4.形成良好的做事习惯

我用两个词形容:聪明和专业。聪明与狡猾不同,聪明是踏实,是勤奋,是诚实,是耐心,是善良(善良是上等智慧)。聪明是不意气用事,是能够理清自己和他人的关系,能认清自己所处的环境和自己的目标,能够从容应对。

而作为一个职场人,要专业。做出的东西要专业,做事的态度要专业、负责,对于自己的产出能够做到文字表述、交付,对于同事之间也要负责,而不是喜欢甩锅。

前端团队/投递资源

阿里所有前端团队:https://yuque.com/alibabaf2e/group/clffqu

堂主:https://yuque.com/zaotalk/ip/dcorln

早早聊大会:https://yuque.com/zaotalk/team/hc

计算机网络

硬件知识

在CPU中至少要有六类寄存器:指令寄存器(IR)、程序计数器(PC)、地址寄存器(AR)、数据寄存器(DR)、累加寄存器(AC)、程序状态字寄存器(PSW)

计算机32和64表示CPU可以处理最大位数,一次性的运算量不一样,理论上64位的会比32位快1倍,内存寻址也不一样。

OSI七层模型

OSI(open system interconnect,开放式系统互联)模型,规定以互联

应用层:为应用程序提供服务

表示层:数据格式转化,数据加密

会话层:建立、管理和维护会话

传输层:建立、管理和维护端到端的连接

网络层:IP选址及路由选择

数据链路层:提供介质访问和链路管理

物理层:物理层

端口位于传输层

tcp五层协议

tcp将应用层、表示层、会话层合并为应用层

TCP对应的应用层协议

  • FTP:定义了文件传输协议,使用21端口。常说某某计算机开了FTP服务便是启动了文件传输服务。下载文件,上传主页,都要用到FTP服务。
  • Telnet:它是一种用于远程登陆的端口,用户可以以自己的身份远程连接到计算机上,通过这种端口可以提供一种基于DOS模式下的通信服务。如以前的BBS是-纯字符界面的,支持BBS的服务器将23端口打开,对外提供服务。
  • SMTP:定义了简单邮件传送协议,现在很多邮件服务器都用的是这个协议,用于发送邮件。如常见的免费邮件服务中用的就是这个邮件服务端口,所以在电子邮件设置-中常看到有这么SMTP端口设置这个栏,服务器开放的是25号端口。
  • POP3:它是和SMTP对应,POP3用于接收邮件。通常情况下,POP3协议所用的是110端口。也是说,只要你有相应的使用POP3协议的程序(例如Fo-xmail或Outlook),就可以不以Web方式登陆进邮箱界面,直接用邮件程序就可以收到邮件(如是163邮箱就没有必要先进入网易网站,再进入自己的邮-箱来收信)。
  • HTTP:从Web服务器传输超文本到本地浏览器的传送协议。

UDP对应的应用层协议

  • DNS:用于域名解析服务,将域名地址转换为IP地址。DNS用的是53号端口。
  • SNMP:简单网络管理协议,使用161号端口,是用来管理网络设备的。由于网络设备很多,无连接的服务就体现出其优势。
  • TFTP(Trival File Transfer Protocal):简单文件传输协议,该协议在熟知端口69上使用UDP服务。

TCP与UDP区别

TCP是有连接,UDP是无连接

TCP是保证数据正确性,UDP可能丢包

TCP只支持点对点通信,UDP支持一对一、一对多、多对一、多对多的通信模式;

TCP是面向字节流的,UDP是面向报文的;

TCP首部开销(20个字节)比UDP的首部开销(8个字节)要大;

TCP有拥塞控制机制;UDP没有拥塞控制,适合媒体通信;

TCP保证可靠性的方式

ACK确认机制、超时重传、滑动窗口、流量控制、丢弃重复数据

TCP流量控制:

如果发送者发送数据过快导致接收者来不及接收,就会有分组丢失。为了避免分组丢失,控制发送者的发送速度使得接收者来得及接收,这就是流量控制。流量控制的根本目的是防止分组丢失,,是TCP可靠性的一方面

实现流量控制的方式:

由滑动窗口协议(连续ARQ协议)实现。滑动窗口协议既保证了分组无差错,有序接收,又保证了流量控制。主要的方式就是接收方返回的ACK中会包含自己接收窗口的大小,并利用大小来控制发送方的数据发送

流量控制与拥塞控制:

拥塞控制是作用于网络的,防止过多的数据注入到网络中,避免网络负载过大的情况。

常用方法:(1)慢开始,拥塞避免,(2)快重传、快恢复

流量控制是作用于接收者的,它是控制发送者的发送速度使接收者来得及接收,防止分组丢失

提高UDP连接可靠性的方法:

1.添加seq/ack机制,确保数据发送到对端,

2.添加发送和接受缓冲区,主要是用户超时重传

3.添加超时重传机制

超时重传机制:

TCP 传输的可靠性是通过序列号和接收方的 ACK 来保证的,当 TCP 传输一个数据段时,它会将该数据段的副本放到重传队列上并开启计时器:

  • 如果发送方收到了该数据段对应的 ACK 响应,当前数据段就会从重传队列中删除;
  • 如果发送方在计时器到期之间都没有收到该数据段对应的 ACK,就会重新发送当前数据段;

TCP 的 ACK 机制可能会导致发送方重新传输接收方已经收到了数据段。TCP 中的 ACK 消息表示该消息之前的全部消息都已经被成功接收和处理,例如:

  1. 发送方向接收方发送了序号为 1-10 的消息;
  2. 接收方向发送方发送 ACK 8 响应;
  3. 发送方认为序号为 1-8 的消息已经被成功接收;

TCP粘包

连续发送两段数据data1和data2时,正常情况下先接收到data1再接收到data2。但是还有别的情况

如先收到data1的部分数据,然后接收到data1的余下部分和data2的全部

或者先收到data1的全部数据和data2的部分数据,然后接收到data2余下的数据

或者一次性接收到data1和data2的全部数据

这三种都是不正常的 属于tcp粘包

发生TCP粘包、拆包主要是由于下面一些原因:

  • 应用程序写入的数据大于套接字缓冲区大小,这将会发生拆包。
  • 应用程序写入数据小于套接字缓冲区大小,网卡将应用多次写入的数据发送到网络上,这将会发生粘包。
  • 进行MSS(最大报文长度)大小的TCP分段,当TCP报文长度-TCP头部长度>MSS的时候将发生拆包。
  • 接收方法不及时读取套接字缓冲区数据,这将发生粘包。

TCP本身是面向流的,作为网络服务器,如何从这源源不断涌来的数据流中拆分出或者合并出有意义的信息呢?通常会有以下一些常用的方法:

  • 1、发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。
  • 2、发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。
  • 3、可以在数据包之间设置边界,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。

TIME WAIT是什么?出现过多的TIME_WAIT可能是什么原因

TIME_WAIT是连接的某一方(可能是客户端也可能是服务端)主动断开连接时,四次挥手等待被断开的一方是否收到最后一次挥手(ACK)的状态。如果是在等待时间中,再次收到第三次挥手表示对方没收到最后一次挥手,这时候要再ACK一次。这个等待的作用是避免出现连接混用的情况

出现大量的TIMEWAIT比较常见的情况是,并发量大,服务器在短时间内断开了大量连接。对应http server的情况是可能没开keep-alive。有keep-alive时,一般是客户端主动断开连接,那么TIMEWAIT就只存在于客户端,而服务端是CLOSEWAIT的状态。如果服务器端出现大量CLOSEWAIT,意味着当前服务器建立的连接被大面积断开。

TCP应用与端到端的服务,UDP应用于广播、收音机等

弱网环境下(丢包率高)影响 TCP 性能的三个原因:

  • TCP 的拥塞控制算法会在丢包时主动降低吞吐量;
  • TCP 的三次握手增加了数据传输的延迟和额外开销;
  • TCP 的累计应答机制导致了数据段的传输;

会议使用udp的原因

UDP面向数据,不需要握手建立连接,不需要滑动窗口,不需要传输层检验和复杂的状态机,客户和服务端个字发送,如果需要考虑丢包的问题,可以扩展增加ACK,因此效率很高,网络带宽利用率高

webrtc

TCP的三次握手与四次握手

TCP连接过程中三次握手:

  • 客户端去连接服务器,
  • 服务器应答客户
  • 客户端回应表示收到,

然后开始发送数据

TCP连接解除时四次挥手:

  • 客户端发送解除报文给服务端
  • 服务确认信息,打开半关闭状态,返回信息
  • 服务端返回信息后再次发送报文
  • 客户端收到信息,准备结束,发送结束报文

为什么是三次握手、四次挥手

为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤。如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认(为什么不能两次握手)

形象化A:能听得到我说话吗 B:听得到,你听得到吗 A:听得到

当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步挥手。(为什么握手三次挥手四次)

形象化:B:我要发送,请接收---A:我接收啦---A:我接收完成啦---B:断开啦

四次挥手为什么要等待两个msl(最大报文段生存时间),也就是ttl寿命

四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIMEWAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIMEWAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

因为server端检测到丢包就需要一个msl,还没等server端重传,client端就CLOSED了

DNS域名解析过程、DNS劫持

DNS(Domain Name System)是域名解析系统,将ip地址与易于记忆的域名连接起来,这样用户就可以输入域名,通过dns服务器访问到对应的ip地址

dns解析:

客户端发送域名请求,如果浏览器缓存中有域名解析的ip地址,直接返回,如果没有在操作系统中的host文件查找,有的话返回ip,如果还没有,回到外网的本地区域名服务器发起查询,如果有直接返回,如果本地区域名服务器没有结果,会向域名服务器发起请求,根域名返回所查询域的主域名服务器地址,客户端再向主域名服务器发起请求,主域名服务器返回此域名对应的域名服务器的地址,也就是你注册的域名服务器,一般来说是域名提供商的服务器地址,本地服务器向域名服务器发出请求,域名服务器返回ip记录,本地服务器得到返回值后返回给浏览器,浏览器得到ip。

递归查询与迭代查询

主机向本地域名服务器是采用递归查询,本地域名服务器向根域名服务器的查询是迭代查询。

递归查询就是如果主机所询问的本地域名服务器不知道被查询的域名的IP地址,那么本地域名服务器就以DNS客户的身份,向其它根域名服务器继续发出查询请求报文(即替主机继续查询),而不是让主机自己进行下一步查询。

迭代查询就是当根域名服务器收到本地域名服务器发出的迭代查询请求报文时,要么给出所要查询的IP地址,要么告诉本地服务器:“你下一步应当向哪一个域名服务器进行查询”。

然后让本地服务器进行后续的查询。根域名服务器通常是把自己知道的顶级域名服务器的IP地址告诉本地域名服务器,让本地域名服务器再向顶级域名服务器查询。

顶级域名服务器在收到本地域名服务器的查询请求后,要么给出所要查询的IP地址,要么告诉本地服务器下一步应当向哪一个权限域名服务器进行查询。

最后,知道了所要解析的IP地址或报错,然后把这个结果返回给发起查询的主机

递归查询时,返回的结果只有两种:查询成功或查询失败.迭代查询,又称作重指引,返回的是最佳的查询点或者主机地址.

dns劫持:

攻击本地dns配置,如修改host文件、缓存等

路由dns劫持,修改路由器的默认配置

对DNS服务器做手脚,或者使用伪造的dns解析服务器,返回假的ip地址或者什么都不做使其失去响应

解决:dns劫持是提供劫持dns解析服务器实现劫持的,使用自己的解析服务器或者提前在app中将解析好的域名以ip的形式发出去就可以绕过运营商dns解析

Http与Tcp协议、Http2、Http1.1

http是运行于tcp协议之上,https运行于ssl/tls之上,ssl/tls运行于tcp之上

http1.1与http1.0的区别

1.HTTP 1.1 改变了 HTTP 协议的语义,默认使用持久连接。即TCP连接默认不关闭,可以被多个请求复用,不用声明 Connection: keep-alive。它的优点与解决的问题在 HTTP 1.0 中已经讲过,在此不敷述。客户端在最后一个请求时,发送Connection: close,明确要求服务器关闭TCP连接。默认情况下建立 TCP 连接不会断开,只有在请求报头中声明 Connection: close 才会在请求完成后关闭连接

2.管道机制:管道机制是指在同一个TCP连接里面,客户端可以同时发送多个请求

缓存

带宽优化和网络连接

增加了错误状态响应码

http1.1的缺点:

虽然 HTTP 1.1 允许复用TCP连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。这称为"队首堵塞"(Head-of-line blocking)。单个 TCP 连接在同一时刻只能处理一个请求,意思是说:两个请求的生命周期不能重叠,任意两个 HTTP 请求从开始到结束的时间在同一个 TCP 连接里不能重叠。

HTTP首部的不断增多,因为所有HTTP首部都是以纯文本形式发送的(不会经过任何压缩),会导致较高的额外负荷。

Http1.1的其他特点:

Chrome 最多允许对同一个 Host 建立六个 TCP 连接。不同的浏览器有一些区别。

http1.1是目前最广泛的http协议

HTTP2

http2的主要特点:

  • 二进制协议 :HTTP/1.1 版的头信息肯定是文本(ASCII编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧。HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。
  • 多工(多路复用):HTTP/2 复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了"队头堵塞"。即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。HTTP 性能优化的关键并不在于高带宽,而是低延迟。多路复用主要指TCP复用。TCP 连接会随着时间进行自我「调谐」,起初会限制连接的最大速度,如果数据成功传输,会随着时间的推移提高传输的速度。这种调谐则被称为 TCP 慢启动。由于这种原因,让原本就具有突发性和短时性的 HTTP 连接变的十分低效。HTTP/2 通过让所有数据流共用同一个连接,可以更有效地使用 TCP 连接,让高带宽也能真正的服务于 HTTP 的性能提升。
  • 头信息压缩:HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如Cookie和User Agent,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。 HTTP2对这一点做了优化,引入了头信息压缩机制(header compression)。一方面,头信息使用gzip或compress压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。

    HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。假定一个页面有100个资源需要加载(这个数量对于今天的Web而言还是挺保守的), 而每一次请求都有1kb的消息头(这同样也并不少见,因为Cookie和引用等东西的存在), 则至少需要多消耗100kb来获取这些消息头。HTTP2.0可以维护一个字典,差量更新HTTP头部,大大降低因头部传输产生的流量。把字符串压缩为字节码

  • 服务器推送: HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push)。 常见场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析HTML源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。

URI、URL、与URN:统一资源标识符、统一资源定位符、统一资源命名

用户发送包含URL、协议版本号,客户机信息

服务机接到请求后给予响应信息,包括协议版本号、成功或者错误的代码、实体信息

客户端接受信息并显示,与服务器断开连接

http2头部压缩原理

在 HTTP/1 中,HTTP 请求和响应都是由「状态行、请求 / 响应头部、消息主体」三部分组成。一般而言,消息主体都会经过 gzip 压缩,或者本身传输的就是压缩过后的二进制文件(例如图片、音频),但状态行和头部却没有经过任何压缩,直接以纯文本传输。每个 HTTP 传输都承载一组标头,这些标头说明了传输的资源及其属性。在 HTTP/1.x 中,此元数据始终以纯文本形式,通常会给每个传输增加 500–800 字节的开销。如果使用 HTTP Cookie,增加的开销有时会达到上千字节。

HTTP2使用的压缩算法为HPACK。这种算法通过服务端和客户端个字维护索引表来实现。索引表又分为静态表和动态表。

静态表中定义了61个Header字段与Index,可以通过传输Index进而获取Header的字段与值,极大减少了报文大小。静态表中的字段和值固定,而且是只读的。静态表中包含常见的头部名称,以及特别常见的头部名称与值的组合;

动态表接在静态表之后,结构与静态表相同,可随时更新。

使用字典可以极大地提升压缩效果,其中静态字典在首次请求中就可以使用。对于静态、动态字典中不存在的内容,还可以使用哈夫曼编码来减小体积。HTTP/2 使用了一份静态哈夫曼码表(详见),也需要内置在客户端和服务端之中。

这种格式支持通过静态霍夫曼代码对传输的标头字段进行编码,从而减小了各个传输的大小。

浏览器可以告知服务端,将 cookie: xxxxxxx 添加到动态字典中,这样后续整个键值对就可以使用一个字符表示了。类似的,服务端也可以更新对方的动态字典。需要注意的是,动态字典上下文有关,需要为每个 HTTP/2 连接维护不同的字典。

HTTP/1 的状态行信息(Method、Path、Status 等),在 HTTP/2 中被拆成键值对放入头部(冒号开头的那些),同样可以享受到字典和哈夫曼压缩。另外,HTTP/2 中所有头部名称必须小写。

HTTP3

HTTP3 是 HTTP2 的复用和压缩,协议从 TCP 更改为 UDP。然后,谷歌的那些人在协议中添加了他们做的层,以确保稳定性、数据包接收顺序及安全性。

HTTP3 在保持 QUIC 稳定性的同时使用 UDP 来实现高速度,同时又不会牺牲 TLS 的安全性。是的,在 QUIC 中就有 TLS1.3,你可以用它发起优雅的 SSL。

QUIC协议中在传输层将数据流作为基本,QUIC流共享相同的QUIC连接,需要额外的握手和慢启动来创建新的QUIC流,通过底层使用UDP协议以及将QUIC数据包封装在UDP数据报的顶部,实现QUIC流的独立交付。因此在大多数情况下,影响一个流的丢包不会影响其他流。

与TCP相比,使用UDP可以提供更大的灵活性,并且可以使QUIC实现完全存在于用户空间中。协议实现的更新不再依赖于操作系统更新。借助QUIC,可以将HTTP级别的流简单地映射为QUIC流的头,从而继承HTTP/2的所有好处,而不会产生队头阻塞问题。

QUIC还结合了典型的3次TCP握手和TLS 1.3的握手。这样默认情况就可以提供加密和身份验证,并且加速连接的建立。就算HTTP会话中的初始请求需要新的QUIC连接,在数据开始流动之前所引起的等待时间也较低。

HTTP协议的特点、针对性优化措施

1.支持客户/服务器模式。

2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。

3.灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type(Content-Type是HTTP包中用来表示内容类型的标识)加以标记。

4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。Keep-Alive 功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive 功能避免了建立或者重新建立连接。市场上的大部分 Web 服务器,包括 iPlanet、IIS 和 Apache,都支持 HTTP Keep-Alive。

5.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。服务器不知道客户端是什么状态。即我们给服务器发送 HTTP 请求之后,服务器根据请求,会给我们发送数据过来,但是,发送完,不会记录任何信息。另一方面,在服务器不需要先前信息时它的应答就较快。两种用于保持 HTTP 连接状态的技术就应运而生了,一个是 Cookie,而另一个则是 Session

http1.1优化措施:

1.减少DNS查询

2.减少Http请求:任何请求都不如不请求快

3.使用CDN:从地理上将数据放到靠近客户端的地方

4.添加Expires首部并配置ETag标签:合理利用浏览器的压缩机制;

5.Gzip资源:所有文本资源都应该使用 Gzip 压缩

6.避免HTTP重定向

长连接与短链接

在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源(如JavaScript文件、图像文件、CSS文件等),每遇到这样一个Web资源,浏览器就会重新建立一个HTTP会话。

从http 1.1开始默认使用长连接,用以保持连接特性,响应头中有:connection:keep-alive。

在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。

注意事项:

存活功能的探测周期太长,还有就是它只是探测TCP连接的存活,属于比较斯文的做法,遇到恶意的连接时,保活功能就不够使了。在长连接的应用场景下,client端一般不会主动关闭它们之间的连接,client与server之间的连接如果一直不关闭的话,会存在一个问题, 随着客户端连接越来越多,server早晚有扛不住的时候,这时候server端需要采取一些策略,

如关闭一些长时间没有读写事件发生的连接,这样可以避免一些恶意连接导致server端服务受损;如果条件再允许就可以以客户端机器为颗粒度,限制每个客户端的最大长连接数, 这样可以完全避免某个蛋疼的客户端连累后端服务。

使用场景

长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,再次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接,如果用短连接频繁的通信会造成socket错误, 而且频繁的socket 创建也是对资源的浪费

而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。

http长连接与websocker长连接

  • HTTP的长连接:HTTP/1.1通过使用Connection:keep-alive进行长连接。在一次 TCP 连接中可以完成多个 HTTP 请求,但是对每个请求仍然要单独发 header,Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。这种长连接是一种“伪链接”,而且只能由客户端发送请求,服务端响应。
  • WebSocket的长连接,是一个全双工的连接,可由服务端主动发起信息。长连接第一次TCP链路建立之后,后续数据可以双方都进行发送,不需要发送请求头。

HTTP请求报文的结构

请求报文由请求报文头部(请求行、请求头部)、空行和请求数据四部分

请求行由请求方法、url、http协议版本3个字段,请求方法有get、post、head、put、options等

请求头部由关键字/值对组成,包括请求的浏览器类型、请求的主机名、

空行表示不再有请求头

请求数据在post中使用,

响应报文的结构

响应报文由响应报文头部(状态行、响应头部)、空行、响应正文三部分

状态行包括http版本、状态码、状态码文本描述

Http首部字段按实际用途分为四个类型:

通用头部字段:请求报文和响应报文都会使用到的字段

请求头部字段:从客户端向服务器发送请求报文时使用的头部,补充请求的附加内容、客户端信息、响应内容相关优先级等信息

响应头部字段:从服务端向客户端返回响应报文时使用的头部,补充响应的附加内容,也会要求客户端附加额外的内容信息

实体头部:补充了资源内容更新时间等与实体有关的信息。

通用头部字段(8):

Cache-Control:控制缓存行为 Connection:连接管理,逐条头部 Date:创建报文的日期时间

Via:代理服务器的相关信息 Warning:错误和警告通知 Upgrade: 升级其他协议

Transfer-Encoding:指定报文传输主体的编码方式 progma:报文指令

请求头部字段(19):

Accept:客户端或者代理能够处理的媒体类型 Accept-language:优先可处理的自然语言

Accept-Encoding:优先可处理的编码格式Accept-Charset:优先可处理的字符集

Host:请求资源所在服务器 User-Agent:客户端信息 Referer:请求原始放的url

TE:传输编码的优先级 Expect:期待服务器的特定行为 Max-Forwards:最大逐跳次数

From:用户的邮箱地址 Range:实体的字节范围请求 If-Ranges资源未更新时发送实体byte的范围请求 If-Modified-Since If-UnModified-Since 比较资源更新时间

Proxy-Authorization:代理服务器要求web认证信息 Authorization: web的认证信息

If-Match: 比较实体标记 If-None-Match: 比较实体标记(与If-Match相反)

响应头部字段(8):

Age:推算资源创建经过的时间 Accept-Range:是否接收字节范围请求 ETag:资源的匹配信息

Vary:代理服务器的管理信息 Server:HTTP服务器的安装信息 Location:令客户端重定向至指定URI

Proxy-Authenticate:代理服务器对客户端的认证信息WWW-Authenticate:服务器对客户端的认证信息

实体头部字段

实体头部字段(10):

Allow:资源可支持的http方法Content-base:

Content-Encoding:实体主体适用的编码方式E-tag

Content-Language:实体主体的自然语言 Content-length:实体主体的大小

Content-Location:替代对应资源的URI、Content-Md5:实体主体的报文摘要

Content-type:实体主体的媒体类型Content-range:实体主体的位置范围

Expires:实体主体过期的日期时间 Last-Modified:资源的最后修改日期时间

Content-type:

文本格式:text/html : html格式 text/plain:纯文本格式 text/xml:xml格式

图片格式:image/gif:gif图片image/jpeg: jpg格式图片 image/png:png图片格式

application类型:appliction/xhtml+xml: xhtml格式 appliction/xml:xml数据格式

​ application/atom+xml:Atom XML聚合格式 application/json:json数据格式

​ application/pdf: pdf格式。 application/msword:word文档格式

​ application/octet-stream:二进制流数据(常见的文件下载)

​ application/x-www-form-urlencoded:form表单数据默认被编码为key/value格式发送到服务器

audio格式:audio/x-wav: wav文件 audio/x-ms-wma:wma文件 audio/map:mp3文件

video格式:video/x-ms-wmv: wmv文件 video/mpeg4: mp4文件 video/avi:avi文件

上传文件:multipart/form-data:文件上传时使用该格式

如果你觉得我的文章对你有帮助的话,希望可以推荐和交流一下。欢迎關注和 Star 本博客或者关注我的 Github