HTTP简介
HTTP是一个属于应用层的面向对象的协议,适用于分布式超媒体信息系统,是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。1960年美国人Ted Nelson构思了一种通过计算机处理文本信息的方法,并称之为超文本(Hyper Text),成为HTTP超文本传输协议标准架构的发展根基。最终,万维网协会(WorldWide Web Consortium)和互联网工程工作小组(Internet Engineering Task Force)共同合作研究HTTP,最终发布了一系列的RFC文档,其中著名的RFC 2616定义了HTTP 1.1协议。
HTTP的主要特点可概括如下:
(1)支持客户端/服务器模式。
(2)简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST,且每种方法规定了客户与服务器联系的类型不同。HTTP简单,使得HTTP服务器的程序规模较小,因此通信速度很快。
(3)灵活:HTTP允许传输任意类型的数据对象,数据的类型由Content-Type加以标记。
(4)无连接 :每次连接只处理一个请求,服务器处理完客户的请求并收到客户的应答后即断开连接。
(5)无状态:协议对于事务处理没有记忆能力。如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另外,在服务器不需要先前信息时它的应答较快。
HTTP的请求报文
HTTP请求由三部分组成,分别是请求行、请求头、请求体 ,一般也会将HTTP的请求行和请求头统一称为请求首部。
HTTP请求的请求行以一个方法(Method)符号开头,以空格分开,后面跟着请求的URI和协议的版本,格式如下:
bash
Method Request-URI HTTP-Version CRLF
其中的Method表示请求方法;Request-URI是一个统一资源标识符;HTTP-Version表示请求的HTTP协议版本;CRLF表示回车和换行(除了作为结尾的CRLF外,不允许出现单独的CR或LF字符)。
HTTP请求报文由3部分组成(请求行+请求头+请求体):
(1)Request Line(请求行 ),包含请求方法、URL地址、协议名称和版本号。
(2)Request Header(请求头),包含若干头部的字段。如有必要,客户程序还可以选择发送的请求头。
大多数请求头并不是必需的,但Content-Length除外 。对于POST请求来说,Content-Length必须出现。常见的请求头字段含义如下:
① Accept:客户端可接受的MIME类型。
② Accept-Charset:客户端可接受的字符集。
③ Accept-Encoding:客户端能够进行解码的数据编码方式,比如gzip。Servlet能够向支持gzip的客户端返回经gzip编码的HTML页面,许多情况下可以减少5~10倍的下载时间。
④ Accept-Language:客户端所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到。
⑤ Authorization:用于设置用户身份信息,如果使用Authorization的方式进行认证,那么每次都要将认证的身份信息(如令牌)放到Authorization头部。
⑥ Content-Length :表示请求消息正文的长度。
⑦ Host :客户端通过这个头部信息告诉服务器想访问的主机名。Host头字段指定请求资源的主机和端口号,必须表示请求URL的原始服务器或网关的位置。HTTP/1.1请求必须包含主机头字段,否则系统会以400状态码返回。
⑧ If-Modified-Since:客户端通过这个头部信息告诉服务器资源的缓存时间。只有当所请求的内容在指定的时间后又经过修改才返回,否则返回304"Not Modified"应答。
⑨ Referer :客户端通过这个头部字段告诉服务器它是从哪个资源来访问服务器的(防盗链)。Referer包含一个URL,表示用户从该URL代表的页面出发访问当前请求的页面。
⑩ User-Agent:包含发出请求的用户信息。
⑪ Cookie :客户端通过这个头部信息往服务器发数据,这是最重要的请求头信息之一。
⑫ Pragma:值为"no-cache",表示服务器必须返回一个刷新后的文档,如果服务器是代理服务器而且已经有了页面的本地缓存副本,则需要进行本地缓存副本的刷新。
⑬ From:值为请求发送者的email地址,由一些特殊的Web客户程序使用,HTTP客户端不会用到。
⑭ Connection :请求完成后是断开连接还是继续保持连接。如果值为"Keep-Alive"或者客户端使用的是HTTP1.1(HTTP 1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如Applet,图片),会显著减少下载所需要的时间。当然,持久连接需要服务端进行配合,服务端需要在应答中发送一个Content-Length头,发送出响应内容的大小。
⑮ Range :用于请求URL资源的部分内容,单位是byte(字节),并且从0开始。如果请求头携带了Range信息,就表示客户端需要进行分批下载或者分段传输。如果服务端支持分批下载,那么服务器会返回状态码206(Partial Content)以及该部分内容。如果服务器不支持分批下载,那么服务器会返回整个资源的大小以及状态码200。
HTTP的响应报文
客户端向HTTP服务端发送请求之后,如果服务器能够正常处理并进行响应,就会向客户端发送HTTP响应。
HTTP的响应报文也由3部分组成(响应行+响应头+响应体)
(1)HTTP响应行:一般由协议版本、状态码及其描述组成,比如"HTTP/1.1 200 OK"。其中,协议版本为HTTP/1.1或者HTTP/1.0, 200是状态码,OK为描述。
(2)响应头:用于描述服务器的基本信息和数据描述,服务器通过这些数据的描述信息可以通知客户端如何处理等一会它回送的数据。
设置HTTP响应头时往往和状态码结合起来。例如,有好几个表示"文档位置已经改变"的状态代码都伴随着一个Location头,而401状态代码则必须伴随一个"WWW-authenticate"头部来表示未授权(Unauthorized)。响应头可以用来完成设置Cookie、指定修改日期、指示浏览器按照指定的间隔刷新页面、声明文档的长度以便利用持久HTTP连接等许多其他任务。
响应码401(Unauthorized)和403(Forbidden)都是拒绝访问的意思,401和403的区别如下:
• 401表示服务端不知道客户端是谁。例如,Token失效、缺失甚至伪造,导致服务端无法识别客户端的身份,这时会返回401,客户端只能重试。
• 403表示服务端已经知道了客户端是谁,但是客户端没有权限去访问该数据资源。例如,客户端登录成功了,但却非要访问自己没有权限访问的内容,这时就会返回403。
常见的响应头字段大致如下:
① Allow:服务器支持哪些请求方法(如GET、POST等)。
② Content-Encoding:文档的编码(Encode)类型,如gzip压缩格式。客户端只有在解码之后才可以得到Content-Type头指定的内容类型。由于服务端返回gzip压缩文档能够显著地减少HTML文档的下载时间,因此服务端应该通过查看Accept-Encoding请求头检查客户端是否支持gzip,为支持gzip的客户端返回经gzip压缩的HTML页面,而为不支持gzip的其他客户端返回普通页面。
③ Content-Length:表示内容长度,只有当客户端使用持久HTTP连接时才需要这个数据。
④ **Content-Type:**表示后面的文档属于什么MIME类型。Servlet程序默认为text/plain,但通常需要显式地指定为text/html。由于经常要设置Content-Type, Servlet程序可以通过调用HttpServletResponse提供了一个专用的setContentType()方法去完成。
⑤ Date:当前的GMT时间,例如"Date:Mon,31Dec200104:25:57GMT"。Date描述的时间表示世界标准时,换算成本地时间,需要知道用户所在的时区。可以用setDateHeader来设置Date,以避免转换时间格式的麻烦。
⑥ Expires:告诉客户端把回送的资源缓存多长时间,-1或0表示不缓存。
⑦ Last-Modified:文档的最后改动时间。和客户端请求头配合使用,客户可以通过请求头If-Modified-Since提供一个起始时间,该请求头将被视为一个条件GET,只有改动时间迟于指定起始时间的文档才会返回,否则返回一个304(Not Modified)状态。
⑧ Location:配合302状态码使用,用于重定向接收者到一个新URI地址,表示客户应当到哪里去提取重定向文档。
⑨ Refresh:告诉客户端隔多久刷新一次,以秒计。
⑩ Server :服务器通过这个头告诉客户端服务器的类型。Server响应头包含处理请求的原始服务器的软件信息。
⑪ **Set-Cookie:**设置和页面关联的Cookie。
⑫ Transfer-Encoding:告诉客户端数据的传送格式。
⑬ WWW-Authenticate:告诉客户端应该在Authorization请求头中提供什么类型的授权信息。如果响应状态码为401(Unauthorized),则应答中这个头是必需的。
HTTP的演进
HTTP在1.1版本之前具有无状态 的特点,每次请求都需要通过TCP三次握手四次挥手 与服务器重新建立连接。比如某个客户端在短时间多次请求同一个资源,服务器并不能区别是否已经响应过用户的请求,所以每次需要重新响应请求、耗费不必要的时间和流量。为了节省资源消耗,HTTP也进行了发展和演进,通过持久连接的方法来进行连接复用 。
HTTP的1.0版本
第一个版本的HTTP是HTTP 0.9,组成极其简单,只允许客户端发送GET这一种请求,且不支持请求头。由于没有协议头,因此HTTP 0.9协议只支持一种内容,即纯文本。不过网页仍然支持用HTML语言格式化,同时无法插入图片。
HTTP的第二个版本为1.0版本,也是第一个在通信中指定版本号的HTTP版本,至今仍被广泛采用。相对于HTTP0.9版本,HTTP 1.0版本增加了如下主要特性:
(1)请求与响应支持头部字段。
(2)响应对象以一个响应状态行开始。
(3)响应对象不只限于超文本。
(4)开始支持客户端通过POST方法向Web服务器提交数据,支持GET、HEAD、POST方法。
(5)支持长连接 ,但默认使用短连接,缓存机制,以及身份认证 。
(6)请求行必须在尾部添加协议版本字段(HTTP 1.0),并且必须包含头部消息。
HTTP 1.0版本支持的请求方式为GET、POST和HEAD;请求访问的资源不再局限于上一个版本的HTML格式,可以根据Content-Type设置访问的格式;同时也开始支持Cache,当客户端在规定时间内访问同一URL资源时,直接访问Cache即可。
HTTP 1.0版本使用Content-Type字段来表示客户端请求服务端的数据是什么格式 ,或者说客户端使用Content-Type来表示具体请求中的媒体类型信息,服务端使用Content-Type来表示具体的响应体中的媒体类型信息。媒体类型(MediaType )的全称为互联网媒体类型(Internet Media Type),也叫作MIME(多用途互联网邮件扩展)类型。表9-5是一些常见的Content-Type字段的值。

HTTP 1.0版本与HTTP 0.9版本还有一个很重要的相同点:默认情况下HTTP 1.0版本的工作方式是每次发送一个请求需要一个TCP连接,当服务器响应后就会关闭这次连接,下一个请求需再次建立TCP连接,这点和HTTP 0.9版本的处理方式是一致的,具体如图9-10所示。

TCP连接的新建成本很高,因为建立连接时客户端和服务器三次握手,并且连接建立之初数据的发送速率较慢。所以,HTTP 1.0版本和HTTP 0.9版本一样,传输性能比较差,随着网页加载的外部资源越来越多,传输的性能问题就愈发突出了。
为了解决这个问题,有些浏览器在请求时对HTTP 1.0版本进行了扩展,增加了一个非标准的Connection头部字段,如果要对传输层的HTTP连接进行复用,Connection头部值如下:
bash
Connection: keep-alive
这个头部字段要求服务器不要关闭TCP连接,以便其他HTTP请求复用,同样服务器需要回应这个字段。
bash
Connection: keep-alive
如果连接的两端都有Connection: keep-alive头部,则一个可以复用的TCP连接就建立了,直到客户端或服务器主动关闭连接。但是,Connection不是标准字段,不同服务端实现的行为可能不一致,因此并不是提高传输性能的最终解决办法。
HTTP的1.1版本
HTTP的第三个版本是HTTP 1.1,是目前使用最广泛的协议版本,也是目前主流的HTTP版本。
HTTP 1.1版本引入了许多关键技术进行传输性能的优化,主要包括持久连接 (Persistent Connection)、管道机制(Pipelining)、分块传输编码(Chunked Transfer Encoding, CTE)、字节范围(Range)请求等。
HTTP 1.1版本的最大变化就是引入了持久连接(Persistent Connection),即下层的TCP连接默认不关闭,可以被多个请求复用,而且报文不用声明"Connection: keep-alive"头部值。在HTTP 1.1版本中,默认情况下一个TCP连接可以允许多个HTTP请求,具体如图9-11所示。
TCP连接如何关闭呢?客户端和服务器都可以进行通信监测,如果发现对方在一段时间没有活动,就可以主动关闭TCP连接。不过,相对规范的做法是,客户端在最后一个请求时发送带**"Connection: close"**请求头的HTTP报文,明确要求服务器关闭TCP连接。
目前,对于同一个域名(带端口),大多数浏览器允许同时建立6个持久连接,这些持久连接在降低了传输延迟的同时也提高了带宽的利用率。
HTTP 1.1版本加入了管道机制,在同一个TCP连接里允许多个请求同时发送,增加了并发性,进一步改善了HTTP协议的效率。举例来说,客户端需要请求两个资源:以前的做法是,在同一个TCP连接里面先发送A请求,然后等待服务器做出回应,收到后再发出B请求;管道机制则是允许浏览器同时发出A请求和B请求,但是服务器还是按照顺序先回应A请求,完成后再回应B请求

HTTP的2.0版本
HTTP的2.0版本(或者说HTTP/2.0协议)是一个二进制协议 。二进制更易于Frame (帧、数据包)的传输。HTTP1.x版本在应用层以纯文本 的形式进行通信,HTTP 2.0将所有的传输信息分割为更小的消息和数据帧 ,并对它们采用二进制格式编码。这样,客户端和服务端都需要引入新的二进制编码和解码的机制,就像前面编写的Protobuf数据帧的编码器和解码器一样。
HTTP/2.0协议有10个不同Frame定义,其中两个最为基础的Frame是Data 帧和Headers帧,其中HTTP/1.x报文的头部信息会被封装到HTTP/2.0报文的Headers帧中,而HTTP/1.x报文的请求体(Request Body)则被封装到HTTP/2.0报文的Data帧中,具体如图9-13所示。

通过以上报文对应关系可以看出,HTTP/2.0协议没有改变HTTP/1.x协议的语义 ,只是在应用层使用二进制分帧方式传输。HTTP 2.0最大的特点是没有改动HTTP的语义,包括HTTP方法、状态码、URI及请求头首部字段等。HTTP/1.x的核心概念在语义上一如往常,但是HTTP/2.0协议却改进了传输性能,实现了低延迟和高吞吐量。
HTTP/2.0协议引入了新的通信单位:帧、消息、流。分帧有什么好处?服务器单位时间接收到的请求数变多,可以提高并发数。最重要的是,为多路复用提供了底层支持。HTTP/2.0协议之所以叫HTTP/2.0版本而不是HTTP/1.2版本,关键在于新增的二进制分帧传输在传输的方式上发生了重大变化。
既然要保证HTTP的各种方法、首部都不受影响,又需要通过二进制进行传输,那就需要在应用层和传输层(TCP/UDP)之间增加一个二进制分帧层 ,在该二进制分帧层 上,HTTP 2.0版本会将所有传输的信息分割为更小的消息和数据帧 ,并对它们采用二进制格式的编码。然后,HTTP 2.0协议的通信都在一个连接上完成,这个连接可以承载任意数量的双向数据流。
HTTP/2协议的主要特点有首部压缩、多路复用、并行双向传输、服务端推送等。
首部压缩
HTTP/2.0协议在客户端和服务端使用"首部(请求头)表"来跟踪和存储之前发送的请求头键-值对,对于相同的数据,不再通过每次请求和响应发送;通信期间几乎不会改变通用键-值对的值(如用户代理、可接受的MIME值等),所以请求头只需发送一次即可。事实上,如果请求中不包含首部(例如对同一资源的请求),那么首部开销就是零字节。此时所有首部都自动使用之前请求发送的首部。
如果请求的首部发生了变化,那么只需要在Headers帧里发送变化了的首部,将新增或修改的首部帧追加到"首部表"即可。首部表中的键-值对在HTTP/2.0协议的TCP连接存续期内始终存在,由客户端和服务器共同渐进地更新。
多路复用
HTTP/2.0协议的多路复用指的是对多资源的请求可以在一个TCP连接上完成。HTTP/2.0协议把HTTP协议通信的基本单位缩小为一个一个的帧,这些帧对应着逻辑流中的消息,并行地在同一个TCP连接上双向交换消息。
实际上,HTTP性能的关键在于低延迟而不是带宽利用率低。大多数HTTP连接的时间都很短,数据传输是突发性的,但是TCP传输只有在长连接并且传输大块数据时其效率才是最高的。HTTP/2.0协议通过让所有数据流共用同一个连接,可以更有效地让TCP连接高带宽,也能真正地服务于HTTP的性能提升。多资源单链接的多路复用方式在服务器和网络传输的层面都得到了好处:
(1)可以减少服务链接压力,内存占用少了,连接吞吐量大了。
(2)由于TCP连接减少而使网络拥塞状况得以改观。
(3)TCP慢启动时间减少,拥塞和丢包恢复速度更快。
并行双向传输
在HTTP/2.0协议中,客户端和服务器可以把HTTP消息分解为互不依赖的帧,然后乱序发送,最后在另一端把它们重新组合起来。注意,同一连接上有多个不同方向的数据流在传输。客户端可以一边乱序发送消息流,也可以一边接收服务器的响应流,而服务器那端同理。
把HTTP消息分解为独立的帧,双向交错发送,然后在另一端重新组装,是HTTP/2.0重要的一项增强。该机制会在整个Web技术栈中引发一系列连锁反应,从而带来巨大的性能提升,大致的原因是:
(1)可以并行交错地发送请求,请求之间互不影响。
(2)可以并行交错地发送响应,响应之间互不干扰。
(3)只使用一个连接即可并行发送多个请求和响应
(4)消除不必要的延迟,从而减少页面加载的时间。
服务端推送
在HTTP/2.0协议中,新增的一个强大的功能就是服务器可以对一个客户端请求发送多个响应。或者说,除了对最初请求的进行响应外,服务器还可以额外向客户端推送资源,而无须客户端明确地请求。
在服务端主动推送这一点上,HTTP/2.0协议和WebSocket协议有点类似。
那么,如何使用HTTP/2.0协议呢?前提是需要Web服务器和浏览器双方都支持,任何一端不匹配,都会回退到HTTP/1.1协议。
总结
HTTP 各个版本协议有什么不同
http主要有4个版本,分别是0.9、1.0、1.1、2.0。
其中0.9版本的协议还不成熟,主要只支持get方式请求,同时也只支持一种请求内容,就是纯文本
然后1.0版本的http在0.9的基础上做了许多的改进,也是一个成熟的协议,他新增了请求头,可以通过请求头来设置实现多种内容的传输,同时也是支持长链接的,只是默认是短连接,需要请求头设置Connection: keep-alive ,不然就是每请求一次就需要tcp的3次握手,4次挥手来建立连接。
然后1.1版本的话在1.0的基础上也修改和增加了一些东西,其中1.1将默认为短连接改为默认是长连接,这样支持一个tcp连接就可以供多个http请求使用(即复用一个tcp连接),同时也增加了管道机制这个功能,其中管道机制的话就是在一个tcp连接中允许多个http请求同时发送,增加了http的并发性。
最后http2.0的话,他是一个二进制协议,他不再是传输文本或者json这些内容,而是通过转换为二进制进行传输,将数据分为多个帧来传输,他有两个基础的帧,分别是Data帧和Headers帧,其中HTTP/1.x报文的头部信息会被封装到HTTP/2.0报文的Headers帧中,而HTTP/1.x报文的请求体(Request Body)则被封装到HTTP/2.0报文的Data帧中,他这样做呢,提高了服务器接受请求的量,提高了并发数,他主要有 首部压缩、多路复用、并行双向传输这几个特效,其中
首部压缩,他是通过一个首部表来实现,将相同数据的请求头进行缓存,所以请求头只需要发送一次即可,后面的传输代价就是0,如果头部发生变化,也只需要将变化的头部信息进行发送,会将变化的首部信息追加到首部表
多路复用,他是真正提供了并行请求和响应的功能,跟1.1的管道机制不同,管道机制仍然存在阻塞的问题,因为他任然是按照顺序响应的,如果一个大文件的响应来了,仍然会阻塞后面的响应,但是2.0的多路复用机制,通过帧的传输,真正的实现了并发的请求和响应,提高了网络的利用率
服务端推送,2.0也实现了在不需要在客户端明确的请求情况下,对客户端进行数据推送,跟websocket相似
HTTP中GET和POST的区别
二者请求数据的放置位置不同
(1)对于GET请求,请求的数据将会附在URL之后。具体来说,请求数据放置在HTTP请求行"Request-Line"的URL后面,以"?"分隔,多个参数之间用"&"连接,例如:
bash
login.action?name=zhangsan&password=123456
如果数据是英文字母和数字,就会原样发送 ;如果数据是特殊字符中的空格,则转义为"+" ;如果是中文或者其他字符,则直接把字符串用BASE64加密 。
(2)对于POST请求,提交的数据将被放置在HTTP请求报文的请求体中。
二者所能传输数据的大小不同
虽然HTTP没有对传输的数据大小进行限制,协议规范也没有对URL长度进行限制,但是在实际开发中是存在限制的:
(1)对于GET请求,特定浏览器和服务器对URL长度有限制 ,例如IE对URL长度的限制是2083字节。对于其他浏览器,如Netscape、FireFox等,理论上没有长度限制,其限制取决于操作系统的支持。因此,GET提交时,传输数据会受到URL长度的限制。
(2)对于POST请求,不是通过URL传值的,理论上数据不受限。实际上各个Web服务器会通过自定义设置对POST提交数据大小进行限制,Tomcat、Apache、IIS6都有各自的配置。
二者传输数据的安全性不同
POST的安全性要比GET的安全性高。通过GET提交数据,用户名和密码将明文出现在URL上,通过查看浏览器的历史记录,就可以拿到其他用户的账号和密码了。这里所说的安全性并不是指传输过程中的数据安全 ,也不是指传输过程中是否对数据进行加密保护,仅仅指的是数据可见性维度的浅层次数据安全。