什么是 HTTP?
HTTP (HyperText Transfer Protocol),即超文本传输协议,是一种实现网络通信的规范。它定义了客户端和服务器之间交换报文的格式和方式,默认使用的是80端口,其底层使用TCP作为传输层协议,保证了数据传输的可靠性。
特点:
- 简单快速:
HTTP协议简单,使得HTTP服务器的规模小,因而通信速度很快。 - 灵活:
HTTP允许传输任意类型的数据对象。 - 无连接:限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。
- 无状态:
HTTP协议无法根据之前的状态进行本次的请求处理。 - 明文:
HTTP是以明文的形式传递内容。
推荐阅读:看完这篇HTTP,跟面试官扯皮就没问题了
HTTP 和 HTTPS 的区别?
HTTPS是HTTP协议的安全版本。HTTPS的出现主要是为了解决HTTP明文传输内容导致其不安全的特性。为保证数据加密传输,让HTTP运行安全的SSL/TLS协议上,即 HTTPS = HTTP + SSL/TLS。通过SSL证书来验证服务器的身份,并为浏览器和服务器之间的通信进行加密。
二者的区别:
- 安全性:
HTTP协议的数据传输是明文的,是不安全的;HTTPS使用了SSL/TLS协议进行加密处理,相对更加安全。 - 连接方式:二者使用的连接方式不同,
HTTP是三次握手,HTTPS是三次握手+数字证书。 - 默认端口:
HTTP的默认端口是80;HTTPS的默认端口是443。 - 响应速度:由于
HTTPS需要进行加解密过程,因此速度不如HTTP。 - 费用:
HTTPS需要使用SSL证书,功能越强大的证书其费用越高;HTTP不需要。
HTTP 1.0 和 1.1 的区别?
连接方式 : HTTP 1.0 为短连接,HTTP 1.1 支持长连接。
状态响应码 : HTTP/1.1中新加入了大量的状态码,光是错误响应状态码就新增了24种。比如说,100 (Continue)——在请求大资源前的预热请求,206 (Partial Content)——范围请求的标识码,409 (Conflict)——请求与当前资源的规定冲突,410 (Gone)——资源已被永久转移,而且没有任何已知的转发地址。
缓存处理 : 在 HTTP1.0 中主要使用 header 里的 If-Modified-Since,Expires 来做为缓存判断的标准,HTTP1.1 则引入了更多的缓存控制策略例如 Entity tag,If-Unmodified-Since, If-Match, If-None-Match 等更多可供选择的缓存头来控制缓存策略。
带宽优化及网络连接的使用 :HTTP1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1 则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
Host头处理 : HTTP/1.1在请求头中加入了Host字段。
推荐阅读:面试常问:HTTP 1.0 和 HTTP 1.1 有什么区别?
HTTP 状态码有哪些?
状态码第一位数字决定了不同的响应状态:
1xx表示请求已被接受,需要继续处理;
2xx表示请求成功;
3xx表示重定向;
4xx表示客户端错误;
5xx表示服务端错误。
常见的状态码:
101:服务器根据客户端的请求切换协议,主要用于websocket或http2升级200:请求已成功,请求所希望的数据将随响应一起返回。201:请求成功并且服务器创建了新的资源。202:服务器已接受响应请求,但尚未处理。301:请求的网页已永久移动至新的位置。302:临时重定向/临时转移。服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。304:本次获取到的内容是读取缓存中的数据,会每次去服务器校验。401:请求需要进行身份验证,尚未认证,没有登录网站。403:禁止访问,服务器拒绝请求。404:服务器没有找到相应资源。500:服务器遇到错误,无法完成对请求的处理。503:服务器无法使用。
TCP 的三次握手和四次挥手?
三次握手🤝:
- 第一次握手:客户端给服务器发送一个
SYN报文。 - 第二次握手:服务器收到
SYN报文后,应答一个ACK报文,同时发出自己的SYN报文,即应答了一个SYN + ACK报文。 - 第三握手:客户端收到
SYN + ACK报文后,回应一个ACK报文。服务器收到ACK报文之后,三次握手完毕。
四次挥手🙋:
- 第一次挥手:客户端认为没有数据需要继续发送,于是向服务器发送一个
FIN报文,申请断开客户端到服务器端的连接,报文中同时会指定一个序列号seq(等于已传送数据的最后一个字节的序号加1)。此时,客户端进入FIN_WAIT_1状态。 - 第二次挥手:服务器接收到
FIN报文后,向客户端发送一个确认报文ACK,表示已经接收到了客户端释放连接的请求,以后不会再接收客户端发送过来的数据。同时会把客户端报文中的序列号seq加1,作为ACK报文中的序列号值。此时,服务端处于CLOSE_WAIT状态。客户端接收到报文之后,进入FIN_WAIT_2状态,等待服务器发送连接释放报文(由于TCP连接是全双工的,此时客户端到服务区器的连接已释放,但是服务器仍可以发送数据给客户端)。 - 第三次挥手:服务器端发送完所有的数据,会向客户端发送一个
FIN报文,申请断开服务器端到客户端的连接。此时,服务器进入LAST_ACK状态。 - 第四次挥手:客户端接收到
FIN报文之后,向服务器发送一个ACK报文作为应答,且把服务器报文中的序列号值加1作为ACK报文的序列号值。此时,客户端就进入TIME_WAIT状态。需要注意的是,该阶段会持续一段时间,以确保服务器收到了该ACK报文。这个时间是2 * MSL(最长报文段时间),如果在这个时间内,没有收到服务器的重发请求,时间过后,客户端就进入CLOSED状态;如果收到了服务器的重发请求就需要重新发送确认报文。服务器只要一收到ACK报文,就会立即进入CLOSED状态。
详细过程可参考:两张动图-彻底明白TCP的三次握手与四次挥手
改成两次握手可以不?
三次握手可以理解为了客户端和服务器互相确认对方的发送和接收能力。如果是两次握手,可以确定服务器的发送和接收能力,但只能确定客户端的发送能力,无法确认其接收能力。另外,如果是两次握手的话,可能会因为网络阻塞等原因会发送多个请求报文,延时到达的请求又会与服务器建立连接,浪费服务器的资源。
GET 和 POST 的区别?
- 参数位置:
GET请求的参数是放在 url 中,POST请求放在请求体 body 中。 - 参数长度:
GET请求在 url 中传递的参数有长度限制(主要是因为浏览器对 url 长度有限制),POST则没有。 - 参数的数据类型:
GET只接受ASCII字符,而POST没有限制。 - 安全:
POST比GET安全,因为数据在地址栏上不可见。但是从传输角度考虑,二者都是不安全的,因为HTTP是明文传输。 - 幂等性:
GET是一个幂等的请求;POST不是。(幂等,指同⼀个请求⽅法执⾏多次和仅执⾏⼀次的效果完全相同) - 缓存:
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
如何解决跨域问题?
首先了解下浏览器的同源策略 同源策略 /SOP(Same origin policy) 是一种约定,由 Netscape 公司 1995 年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到 XSS、CSFR 等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个 ip 地址,也非同源
JSONP:Jsonp(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据。ajax 请求受同源策略影响,不允许进行跨域请求,而 script 标签 src 属性中的链接却可以访问跨域的 js 脚本,利用这个特性,服务端不再返回 JSON 格式的数据,而是返回一段调用某个函数的 js 代码,在 src 中进行了调用,这样实现了跨域。CORS:CORS(Cross-origin resource sharing)跨域资源共享,服务器设置对 CORS 的支持。其原理是,服务器设置 Access-Control-Allow-Origin HTTP响应头之后,浏览器将会允许跨域请求。实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。proxy代理:最常用多方式。通俗点说就是客户端浏览器发起一个请求会存在跨域问题,但是服务端向另一个服务端发起请求并无跨域,因为跨域问题归根结底源于同源策略,而同源策略只存在于浏览器。那么我们可以通过 Nginx 配置一个代理服务器,反向代理访问跨域的接口,并且我们还可以修改 Cookie 中 domain 信息,方便当前域 Cookie 写入。
参考链接:跨域,不可不知的基础概念
- 通过 jsonp 跨域
使用 jsonp 来实现跨域请求,它的主要原理是通过动态构建 script 标签来实现跨域请求,因为浏览器对 script 标签的引入没有跨域的访问限制 。通过在请求的 url 后指定一个回调函数,然后服务器在返回数据的时候,构建一个 json 数据的包装,这个包装就是回调函数,然后返回给前端,前端接收到数据后,因为请求的是脚本文件,所以会直接执行,这样我们先前定义好的回调函数就可以被调用,从而实现了跨域请求的处理。这种方式只能用于 get 请求。
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参并指定回调执行函数为onBack
script.src = '<http://www>.....:8080/login?user=admin&callback=onBack';
document.head.appendChild(script);
// 回调执行函数
function onBack(res) {
alert(JSON.stringify(res));
}var script = document.createElement('script');
script.type = 'text/javascript';
// 传参并指定回调执行函数为onBack
script.src = '<http://www>.....:8080/login?user=admin&callback=onBack';
document.head.appendChild(script);
// 回调执行函数
function onBack(res) {
alert(JSON.stringify(res));
}- 使用 CORS 的方式
CORS 是一个 W3C 标准,全称是"跨域资源共享"。CORS 需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,因此我们只需要在服务器端配置就行。浏览器将 CORS 请求分成两类:简单请求和非简单请求。对于简单请求,浏览器直接发出 CORS 请求。具体来说,就是会在头信息之中,增加一个 Origin 字段。Origin 字段用来说明本次请求来自哪个源。服务器根据这个值,决定是否同意这次请求。对于如果 Origin 指定的源,不在许可范围内,服务器会返回一个正常的 HTTP 回应。浏览器发现,这个回应的头信息没有包含 Access-Control-Allow-Origin 字段,就知道出错了,从而抛出一个错误,ajax 不会收到响应信息。如果成功的话会包含一些以 Access-Control- 开头的字段。
- nginx 代理跨域
- 使用 websocket 协议,这个协议没有同源限制。
正向代理和反向代理?
正向代理隐藏了真实的请求客户端,服务端不知道真实的客户端是谁,客户端请求的服务都被代理服务器代替来请求。
反向代理隐藏了真实的服务端,当发送一个请求时,其背后可能有很多台服务器为我们服务,但具体是哪一台,我们不知道,也不需要知道,我们只需要知道反向代理服务器是谁就好了,反向代理服务器会帮我们把请求转发到真实的服务器那里去。反向代理器一般用来实现负载平衡。
DNS 协议?
概念:
DNS(Domain Namse System),域名系统,是进行域名和其相应IP地址进行转换的服务器。可以将DNS理解为一个翻译官,负责把域名转换为相应的IP地址。DNS协议运行在UDP协议之上,使用53号端口。域名:
域名是一个具有层次的结构,如下:
bashbash复制代码 主机名.次级域名.顶级域名.根域名 # 即host.sld.tld.rootbash复制代码 主机名.次级域名.顶级域名.根域名 # 即host.sld.tld.root需要注意的是,根域名
.root对于所有域名都是一样的,所以平时是省略的。根据域名的层级结构,管理不同层级域名的服务器,可以分为
根域名服务器、顶级域名服务器和权限域名服务器。除此之外,还有电脑默认的本地域名服务器。查询方式:
DNS查询方式分为递归查询和迭代查询两种。所谓递归查询,就是A向B请求,如果B不知道所请求的内容,则B将继续向上请求,直到获得所需的内容,然后将内容返回给A。迭代查询,就是A向B请求,如果B不知道,则B会告诉A如何获得该内容,让A继续去请求。域名缓存:
域名服务器会缓存域名和IP之间的映射。分为两种缓存方式:
①
浏览器缓存:浏览器在获取网站域名的地址后会对其进行缓存,减少网络请求的损耗。②
操作系统缓存:操作系统的缓存其实是用户自己配置的 hosts 文件。完整解析过程:
- 首先搜索浏览器的 DNS 缓存,缓存中维护一张域名与 IP 地址的对应表
- 若没有命中,则继续搜索操作系统的 DNS 缓存
- 若仍然没有命中,则操作系统将域名发送至本地域名服务器,本地域名服务器查询自己的 DNS 缓存,查找成功则返回结果
- 若本地域名服务器的 DNS 缓存没有命中,则本地域名服务器向上级域名服务器进行查询,通过以下方式进行
迭代查询:- 首先本地域名服务器向根域名服务器发起请求,根域名服务器返回顶级域名服务器的地址
- 本地域名服务器拿到这个顶级域名服务器的地址后,向其发起请求,获取权限域名服务器的地址
- 本地域名服务器根据权限域名服务器的地址向其发起请求,最终得到该域名对应的 IP 地址
- 本地域名服务器将得到的 IP 地址返回给操作系统,同时自己将 IP 地址缓存起来
- 操作系统将 IP 地址返回给浏览器,同时自己也将 IP 地址缓存起来
- 至此,浏览器就得到了域名对应的 IP 地址,并将 IP 地址缓存起来
参考链接:超详细 DNS 协议解析
从输入URL到看到页面的过程,发生了什么?
url解析:首先会判断输入的是一个合法 url还是关键词,并根据输入的内容进行相应的操作。查找缓存:浏览器会判断所请求的资源是否在浏览器缓存中,以及是否失效。如果没有失效就直接使用;如果没有缓存或失效了,就继续下一步。DNS解析:此时需要获取url中域名对应的IP地址。浏览器会依次查看浏览器缓存、操作系统缓存中是否有ip地址,如果缓存中没有就会向本地域名服务器发起请求,获取ip地址。本地域名服务器也会先检查缓存,有则直接返回;如果也没有,则采用迭代查询方式,向上级域名服务器查询。先向根域名服务器发起请求,获取顶级域名服务器的地址;再向顶级域名服务器发起请求以获取权限域名服务器地址;然后向权限域名服务器发起请求并得到url中域名对应的IP地址。建立TCP连接:根据ip地址,三次握手与服务器建立TCP连接。发起请求:浏览器向服务器发起HTTP请求。响应请求:服务器响应HTTP请求,将相应的HTML文件返回给浏览器。关闭TCP连接:四次挥手关闭TCP连接。渲染页面:浏览器解析HTML内容,并开始渲染。浏览器渲染过程如下:构建DOM树:词法分析然后解析成DOM树,DOM树是由DOM元素及属性节点组成,树的根是document对象。构建CSS规则树:生成CSS 规则树。构建渲染树:将DOM树和CSS规则树结合,构建出渲染树。布局:计算每个节点的位置。绘制:使用浏览器的UI接口进行绘制。
为什么 HTTP 协议要基于 TCP 来实现?
TCP 是一个端到端的可靠的连接协议,HTTP 基于传输层 TCP 协议不用担心数据传输的各种问题(当发生错误时,会重传)
推荐阅读:从输入URL开始建立前端知识体系
即时通讯的实现方式?
主要有四种方式,它们分别是轮询、长轮询(comet)、长连接(SSE)、WebSocket。它们大体可以分为两类,一种是在HTTP基础上实现的,包括短轮询、comet和SSE;另一种不是在HTTP基础上实现是,即WebSocket。
轮询短轮询的基本思路就是浏览器每隔一段时间向浏览器发送http请求,服务器在收到请求后,不论是否有数据更新,都直接进行响应。这种方式实现的即时通信,本质上还是浏览器发送请求,服务器接受请求的一个过程,通过让客户端不断的进行请求,使得客户端能够模拟实时地收到服务器端的数据的变化。 优点:比较简单,易于理解,实现起来没有什么技术难点。 缺点:由于需要不断的建立http连接,严重浪费了服务器端和客户端的资源。长轮询当服务器收到客户端发来的请求后,服务器端不会直接进行响应,而是先将这个请求挂起,然后判断服务器端数据是否有更新。如果有更新,则进行响应;如果一直没有数据,则到达一定的时间限制(服务器端设置)才返回。 优点:长轮询和短轮询比起来,明显减少了很多不必要的http请求次数,相比之下节约了资源。 缺点:连接挂起也会导致资源的浪费。长连接SSE是HTML 5新增的功能,全称为Server-Sent Events。它可以允许服务推送数据到客户端。SSE在本质上就与之前的长轮询、短轮询不同,虽然都是基于http协议的,但是轮询需要客户端先发送请求。而SSE最大的特点就是不需要客户端发送请求,可以实现只要服务器端数据有更新,就可以马上发送到客户端。 优点:不需要建立或保持大量的客户端发往服务器端的请求,节约了很多资源,提升应用性能;实现非常简单,并且不需要依赖其他插件。WebSocketWebSocket是HTML 5定义的一个新协议,与传统的http协议不同,该协议可以实现服务器与客户端之间全双工通信。简单来说,首先需要在客户端和服务器端建立起一个连接,这部分需要http。连接一旦建立,客户端和服务器端就处于平等的地位,可以相互发送数据,不存在请求和响应的区别。 优点:实现了双向通信。 缺点:服务器端的逻辑非常复杂。
谈一谈浏览器的缓存机制?
web 资源的缓存策略一般由服务器来指定,可以分为两种,分别是强缓存策略和协商缓存策略。
使用强缓存策略时,如果缓存资源有效,则直接使用缓存资源,不必再向服务器发起请求。强缓存策略可以通过两种方式来设置,分别是 http 头信息中的 Expires 属性和 Cache-Control 属性。
- Expires 属性:指定资源的过期时间。在过期时间以内,该资源可以被缓存使用,不必再向服务器发送请求。这个时间是一个绝对时间,它是服务器的时间,因此可能存在这样的问题,就是客户端的时间和服务器端的时间不一致,或者用户可以对客户端时间进行修改的情况,这样就可能会影响缓存命中的结果。
- Cache-Control 属性:为了解决 expires 的缺陷而提出,它提供了对资源的缓存的更精确的控制。我们可以通过设置 max-age 来指定资源能够被缓存的时间的大小**,这是一个相对的时间,它会根据这个时间的大小和资源第一次请求时的时间来计算出资源过期的时间。**private ,用来规定资源只能被客户端缓存,不能够代理服务器所缓存。还有如 no-store **,用来指定资源不能够被缓存,**no-cache 代表该资源能够被缓存,但是立即失效,每次都需要向服务器发起请求。
一般来说只需要设置其中一种方式就可以实现强缓存策略,当两种方式一起使用时,Cache-Control 的优先级要高于 Expires 。
使用协商缓存策略时,会先向服务器发送一个请求,如果资源没有发生修改,则返回一个 304 状态,让浏览器使用本地的缓存副本。 如果资源发生了修改,则返回修改后的资源。协商缓存也可以通过两种方式来设置,分别是 http 头信息中的 Etag 和 Last-Modified 属性。
服务器通过在响应头中添加 Last-Modified 属性来指出资源最后一次修改的时间,当浏览器下一次发起请求时,会在请求头中添加一个 If-Modified-Since 的属性,属性值为上一次资源返回时的 Last-Modified 的值。当请求发送到服务器后服务器会通过这个属性来和资源的最后一次的修改时间来进行比较,以此来判断资源是否做了修改。如果资源没有修改,那么返回 304 状态,让客户端使用本地的缓存。如果资源已经被修改了,则返回修改后的资源。使用这种方法有一个缺点,就是Last-Modified 标注的最后修改时间只能精确到秒级,如果某些文件在 1 秒钟以内,被修改多次的话,那么文件已将改变了但是 Last-Modified 却没有改变,这样会造成缓存命中的不准确。
因为 Last-Modified 的这种可能发生的不准确性,http 中提供了另外一种方式,那就是Etag 属性**。服务器在返回资源的时候,在头信息中添加了 Etag 属性,这个属性是资源生成的唯一标识符,当资源发生改变的时候,这个值也会发生改变。在下一次资源请求时,浏览器会在请求头中添加一个 If-None-Match 属性,这个属性的值就是**上次返回的资源的 Etag 的值。服务接收到请求后会根据这个值来和资源当前的 Etag 的值来进行比较,以此来判断资源是否发生改变,是否需要返回资源。通过这种方式,比 Last-Modified 的方式更加精确。
当 Last-Modified 和 Etag 属性同时出现的时候,Etag 的优先级更高。使用协商缓存的时候,服务器需要考虑负载平衡的问题,因此多个服务器上资源的 Last-Modified 应该保持一致,因为每个服务器上 Etag 的值都不一样,因此在考虑负载平衡时,最好不要设置 Etag 属性。
强缓存策略和协商缓存策略在缓存命中时都会直接使用本地的缓存副本,区别只在于协商缓存会向服务器发送一次请求。它们缓存不命中时,都会向服务器发送请求来获取资源。在实际的缓存机制中,强缓存策略和协商缓存策略是一起合作使用的。浏览器首先会根据请求的信息判断,强缓存是否命中,如果命中则直接使用资源。如果不命中则根据头信息向服务器发起请求,使用协商缓存,如果协商缓存命中的话,则服务器不返回资源,浏览器直接使用本地资源的副本,如果协商缓存不命中,则浏览器返回最新的资源给浏览器。

