谈谈你对http的理解
HTTP是超文本传输协议。
- 首先,它是一个计算机协议,它使用计算机能够理解的语言确立了一种计算机之间的通信规范。
- 其次,它是一个双向传输协议,它确定了两端之间传输数据的约定和规范,这里抽象出的两端就是服务端和客户端,对于下层是如何传输http是不考虑的。
- 最后,它是一个超文本传输协议。超文本就是我们在生活中能够感知到的图片、音频、视频、HTML页面等。HTTP规定了传输超文本的规范,也实现了超媒体的高效传输。
聊一下请求报文
HTTP报文是用ASCII码文本书写的。它由报文首部、空行、报文主体组成。
报文首部:
请求首部 = 请求方法、URL、HTTP版本(请求行) + 请求头部
响应首部 = 状态码、HTTP版本(状态行) + 响应头部通用首部字段:
Cache-Control:操纵缓存服务器的行为;
Connection:告诉服务器不转发哪个字段、管理持久连接;
Date:表明HTTP报文的创建时期与时间;
Transfer-Encoding:chunked:传输报文主体时采用的编码方式;
请求首部字段:
Accept:通知服务器用户代理能够处理的媒体类型,比如text/html、image/jpeg等;
Accept-Charset:通知服务器 用户代理能够处理的字符集;
Accept-Encoding:通知服务器用户代理能够处理的编码;
Host:告诉服务器我所请求的资源在哪个主机名+端口号上;
User-Agent:传递浏览器信息 用户代理信息给服务器
响应首部字段:
Accept-Ranges:告诉客户端服务器能够处理的请求范围 none/bytes
实体首部字段:
Allow:通知客户端我能支持的HTTP方法 若失败则返回405;
Content-Encoding:告诉客户端我对内容的编码方式;
Content-Location:报文主体返回的URI、Content-Type实体主体内对象的媒体信息;
Expires:告诉客户端资源失效的日期,如果缓存服务器收到了Expires响应后,会在过期前都以缓存来应答请求、Cookie告诉服务器自己要发送cookie、Set-Cookie设置cookie的属性
Content-Length:消息实体的总长度,若主体内容进行分块传输就不能有则Content-length(因为Content-length要求实体长度必须精确一致,而分块传输就是用于消息长度不确定,产生矛盾) 请求方法
GET:从服务器获取资源,可以与POST混用,只不过GET没有请求体。
POST:POST提交的实体是请求URI的从属物,表示该URI能够处理此请求实体。(而PUT的URI一般表示同一个资源的不同版本)
PUT:把请求实体放在请求URI上,若该客户端资源在服务器已存在,那么此次PUT的客户端资源就代表着一个新版本,会覆盖旧版本。那么此次PUT操作到底是创建还是新增,客户端会通过服务器返回的响应码来判断(已创建201、已改变200)
DELETE:删除方法,幂等方法
幂等性:多次执行相同的操作,结果都是相同的。
GET肯定是幂等的。
POST的语义是提交数据创建资源,不是幂等的(POST会发送两个数据包,头体分开发送)如果我们需要服务器认为 连续两次发送相同的请求结果不一致,则需要发送POST请求。
PUT是把客户端资源封装在请求URI标识下,若之前有此资源则覆盖。一般用于更新数据,多次相同的更新结果相同。
GET与POST的区别
①从功能上讲,GET一般用来从服务器上获取资源,它的语义是获取数据;POST一般用来更新服务器上的资源,它的语义是提交数据。
②从幂等上讲,GET是幂等的,即读取同一个资源总是获得相同的数据;POST不是幂等的,因为每次请求对资源的改变不一定相同。也就是说,GET不会改变服务器上的资源,POST会改变服务器上的资源。
③从请求参数上讲,GET请求的参数会附在URL之后,即请求数据放在HTTP报文的请求头中;而POST请求会把提交的数据放置在HTTP请求报文的请求体中。(补充:GET请求参数若为英文/数字,则原样发送;否则将其编码为application/x-www-form-ulencoded MIME字符串。若为空格会转换为+,若为中文/其他字符,则会BASE64加密)
④从安全性上讲,POST请求比GET请求更加安全。因为GET请求参数以明文形式附在URL上,而POST请求则被包装在请求体中
⑤从请求的长度上讲,GET请求的长度受限于浏览器/服务器对URL长度的限制,允许发送的数据量比较小,而POST请求没有大小限制。
⑥从发送方式上讲,一般GET请求是一次性发送,但如果URI太长TCP也会把GET请求报文分两次发送。而POST请求一般会产生两个数据包,浏览器会先发送请求头,服务器收到后响应100,浏览器收到100再发送请求体。但对于火狐浏览器,比较小的POST请求也是一次发送。
⑦特别的,GET请求会被浏览器主动缓存,它在浏览器回退/前进是无害的;而POST请求回退/前进就会重新提交
状态码
客户端发送请求,获得响应报文后需要通过状态码知道请求是否被正确处理、从而确定下一步应该执行什么
- 1xx:请求已经接收到,但需要进一步处理才能完成
- 200:服务器已正常处理请求。
- 201:新资源在服务器成功创建
- 206:使用range协议时返回部分响应内容时的响应码
- 301:资源已被永久重定向。(书签会被重新保存)
- 302:资源被临时重定向。(书签不会被更新)
- 303:重定向到其他资源,常用于POST/PUT请求的响应中,表示客户端应该使用GET方法访问资源
- 304:客户端拥有可能过期的缓存时,会携带缓存标识等信息询问服务器缓存是否可以复用,而304是告诉客户端可以复用缓存(即使缓存过期了)。304一般用于缓存重定向。请求头包含if-modified-since条件表示客户端有缓存且资源未修改,服务端收到此条件进行缓存控制(判断缓存是否需要失效等)
- 400:客户端的请求报文中出现语法错误
- 401:发送的请求需要通过HTTP认证
- 403:客户端对请求资源的访问被服务器拒绝,可能是访问权限等问题。
- 404:没有找到服务器上请求的资源
- 405:服务器不支持请求行中的method方法
- 500:服务器执行时发生了错误
- 502 Bad Gateway:代理服务器无法连接到源服务器、无法从源服务器中获取到合法响应。
- 503:服务器资源尚未准备好处理当前请求
- 504 Gateway Timeout:代理服务器与源服务器之间发生超时
空行
报文主体
请求体:
若方法为GET则没有请求体,
若方法为POST上传文件时键值对以分号分隔、普通表单提交以键值对+&分隔、raw格式以json提交、还可以以XML格式发送。
响应体:
HTML源文件、传输的数据
对于报文主体消息的数据过长的情况,HTTP协议并没有规定要拆分发送,但我们服务器一般会有个阈值,超过阈值就拆分发送。
HTTP1.0/1.1/2.0
HTTP/1.0:
①HTTP/1.0除了基本请求行外,还具有了KV结构的请求头、响应头信息,可以根据请求头与响应体的协商完成多种不同类型数据的传输(比如期望的文件类型、编码类型、语言、压缩格式)。
②HTTP/1.0通过请求头和响应体实现了很多特性:
状态码:服务器告知浏览器自己的请求处理情况
Cache机制:缓存已经下载过的数据
用户代理:请求头中的用户代理字段统计客户端的基础信息。
HTTP/1.1:
相对于HTTP/1.0的改进:
①HTTP1.0每进行一次通信都要建立一个TCP连接。HTTP/1.1实现了长连接,它通过减少TCP建立连接和断开连接的次数减少了服务器额外的负担。HTTP/1.1中长连接默认开启,我们可以在请求头中添加Connection:close关闭长连接。
②HTTP1.0中每个域名都有一个唯一的IP地址与之对应。但随着技术的发展,需要实现一台主机绑定多个虚拟主机,即多个域名共用一个IP地址。所以HTTP1.1的请求头中增加了Host字段,来表示当前域名。
③HTTP1.0中响应头的Content-Length告知了浏览器需要接收的文件大小。但随着技术发展很多页面都是动态生成的,浏览器不知道何时能够完成所有文件数据的接收。所以HTTP/1.1引人入了Chunked分块编码,服务器会把数据分割成块并在发送时附带上一个数据块的长度,浏览器就可以动态地接收数据。
④客户端Cookie机制
⑤安全机制
HTTP/2.0:
①在HTTP/1.1中,报文头部会携带许多头字段,导致浪费大量带宽。所以HTTP/2.0对头部进行压缩,使用HPACK算法,在客户端与服务器两端建立字典,用索引号表示重复的字符。
②在HTTP/1.1中采用Chunked分块编码,HTTP/2.0直接把报文头与报文体分隔为多个二进制的帧进行传输,体积小速度快。
③正因为HTTP/2.0采用二进制的帧传输,所以HTTP/2.0定义了流这个概念,流是一个二进制帧的双向传输序列,每个帧都会附带一个唯一的流ID。所以HTTP/2.0可以多路复用TCP,帧通过流到达对端时,对端根据流ID对帧进行分组并组装成请求报文和响应报文。避免了HTTP/1.1的队头阻塞问题(一个TCP连接同一时刻只能处理一个请求,其他请求会被阻塞)。并且HTTP/2.0中服务器也可以创建流并主动发送给客户端,可以提前把JS、CSS等推送给浏览器,加快响应速度。
④HTTP/2.0可以多路复用TCP,就导致了一个TCP连接中同时传输多个不完整的Frame,可能会导致所有Frame都没有发送完整就引发了TCP连接的流量控制,造成了Stream阻塞,影响了并发量。所以HTTP/2.0提供了应用层流量控制:它是通过window_update帧来实现流控的。发送端与接收端设置独立流控,一端流量到达设定上限时会发出指令通知对端,只有Data帧服从流量控制。
⑤在HTTP/1.1中,TCP的慢启动、TCP连接之间竞争固定的带宽都导致带宽利用率下降。所以HTTP/2.0限制一个域名只能使用一个TCP长连接来传输数据,也就是说一个页面的下载资源只需要一次TCP慢启动,也避免了一个页面的多个TCP连接的竞争问题。
⑥HTTP/2.0都是使用https协议名的,也就是跑在TLS上面的,保证了安全传输。
连接相关
短连接:
客户端每次发送请求前先与服务器建立连接,发送请求收到响应后立即关闭连接。应用场景:Web网站?因为客户端量太大,导致长连接量大占用大量资源
HTTP长连接:
客户端向服务器发送请求时会建立TCP长连接,后续的请求都会复用这个TCP长连接。设置Connection:keep-alive开启当前TCP的长连接,HTTP/1.1长连接默认开启。HTTP长连接需要设置超时时间,防止大量空闲长连接消耗服务器资源。可以设置报文头Keep-Alive:timeout xxx、Connection:close
应用场景:点对点的频繁、连接数不会太多的通信,比如数据库连接。
TCP长连接
keepalive机制通过心跳包保证TCP存活。客户端定期发送心跳包,服务端接收到客户端的心跳包后会响应数据包。若客户端在一定时间内没有收到服务端的数据包,则会断开TCP连接。
TCP的keepalive机制通过心跳检测用来保证TCP长连接的存活,也用来防止大量空闲TCP连接占用内存。
HTTP的keep-alive机制用来管理TCP长连接,可以使得支撑他的TCP长连接存活的更久。(当然HTTP的Connection的值设置为keep-alive代表开启长连接)
浏览器可以为每个域名最多维持6个TCP长连接。
TCP的默认心跳周期是2小时。
其他
说说forward与redirect
Forward与Redirect都是请求转发。
Forward是直接转发,服务器把请求直接转发到另一台服务器上,HTTP头部的X-Forwarded-For就用于在多个代理服务器之间传递客户端IP。
Redirect是间接转发,服务器会返回给浏览器让它重新请求另一台服务器。转发后浏览器地址会发生变化、它的数据在两次请求中不共享。
重定向流程:当浏览器接收到重定向响应码时,会读取响应Location头部的值,获取新的URI再跳转访问该页面
说一下Web缓存
Web缓存器也叫代理服务器,它会缓存服务器响应给客户端的对象以便下次访问。若浏览器配置了优先使用缓存,则浏览器请求是先会向Web缓存器发送HTTP请求,若Web缓存器有对象副本则直接返回HTTP响应;若没有对象副本则Web缓存器会向服务器发送HTTP请求,接收响应并拷贝,然后再发送给客户端。它可以大大减少客户端请求的响应时间。CDN就是一种web缓存技术。(缓存结构为key-URL,key由红黑树、哈希表等字典存放)
如果缓存过期了,服务器返回响应码304,表明虽然缓存过期了但客户端仍然可以继续使用。
说一下cookie和session
HTTP是一种无状态协议,要想保存数据供多次请求使用,就要用到cookie与session来实现有状态的HTTP请求。
客户端第一次请求服务器时,如果服务器需要记录该用户状态,那么服务器会把用户信息保存到session中,然后在响应时会向客户端颁发一个cookie。客户端把cookie保存在浏览器上,再次请求该网站时客户端会携带cookie,服务器检查cookie中的用户状态与session的一致性。
cookie由服务器生成,保存在浏览器。服务端生成Cookie后在响应中通过Set-Cookie头部告知客户端,客户端得到Cookie后,后续请求都会自动将Cookie头部放到请求头中
cookie是不可跨域的。因为cookie是基于浏览器保存的,所以域名不同,无法跨域访问。
cookie中可以包含的数据类型:String名称、O别处他数据、int失效时间、版本号等。
cookie被禁用后,session还是可以用的。我们可以通过get、post请求参数为服务器提供sessionid。
HTTP传输大文件
①压缩传输:请求头Accept-Encoding,响应头Content-Encoding规定压缩格式,但实际上图片音视频等多媒体数据本身已经是高度压缩了,所以此方法只对文本文件效果显著。
②分块传输:把文件分解成多个小块,对端收到小块后再组装复原。这样浏览器和客户端都不需要在内存中存储整个文件,而且每次都只收发一小块,不会占用太大的网络带宽。每个分块都包含一个长度头和数据块,长度头存放16进制的长度,两者都以CRLF(/r/n)结尾。
③范围请求:运行客户端在请求头中使用Range字段表示只获取文件的一部分。
④多段请求:MIME=multipart/byteranges,请求头boundary=xxx给出段之间的分隔标记。
包帧流
帧格式:
streamID实现了多路复用,即多个线程同时发送,帧穿插传输,根据streamID组装。但同一个Stream内的frame必须是有序的,所以无法实现并发。
length:帧长度为2的14次方-1大小之前时,支持16KB以下的帧,帧长度为2的14次方大小之后时,接收端必须首先公布自己可以处理的大小。
type:包括HTTP包体帧、HTTP头部帧、Stream优先级帧、终止Stream帧、PING心跳检测帧、流量控制帧、大HTTP头部帧、通知接收方一些信息的帧
Stream优先级:使用优先级帧来表示Stream的优先级。帧中有流依赖字段、有Weight字段代表数据流优先级。 包: 当发送端可以确定包体的全部长度时,使用Content-Length头部明确指明包体长度。若无法明确时则使用Transfer-Encoding头部明确指定使用Chunk传输方式。一个chunk块 = chunk-size十六进制编码 + chunk-data二进制编码
多线程断点续传、随机点播
HTTP Range:运行服务器基于客户端的请求只发送响应包体的一部分到客户端,发送完成后,客户端自动将多个片段的包体组合成完整的体积更大的包体(请求头Range发送当前长度,服务端会响应206,Content-Range头部会显示当前片段包体在完整包体中的位置)
跨域
跨域实际上是同源策略的结果,即浏览器拦截了协议、域名、端口中任意一个与之不同的响应数据,。若没有同源策略,用户访问站点A后收到的响应可能会自动去访问站点B,即不能保证请求是用户自愿发出的。
CORS解决跨域:①客户端发送简单请求(get/head/post)时要告知服务器请求的站点来源,服务器发送的响应头中配置携带Access-Control-Allow-Origin:xxx。②使用预检请求,使用Access-Control-Request-xxx预检请求头部,使用Access-Control-Allow-xxx预检响应头部。
CSRF攻击:①跨域请求伪造攻击,用户的表单提交不受跨域限制,所以用户的cookie可能会存在攻击。②攻击者仿造表单伪站点,我们可以通过服务器Token验证伪站点。