关于HTTP协议的基本介绍。
HTTP协议是基于TCP/IP协议之上的应用层协议,主要用于规定互使用联网中客户端和服务器之间的通信格式,不关心具体传输细节,默认80端口。对于Web开发,不管是前端还是后端开发,了解HTTP协议是必备的一些基本知识。
发展历程
HTTP/0.9
于1991年发布,只有一个GET命令,返回HTML格式内容。
HTTP/1.0
于1996年5月发布,增加POST、HEAD命令,传输内容可以说任意格式,不再仅限于HTML,并且报文规定了一些元数据字段,比如字符集、状态码、编码、缓存等。
HTTP/1.1
于1997年1月发布,增加PUT\PATCH\DELETE等命令,并新增了一些功能机制:
- 持久连接(keep-alive可保持长连接,减少重复请求)。
- 管道机制(pipelining,一个TCP连接中客户端可同时发送多个请求)。_Content-Length字段_(报文内容长度)。
- Host字段(用于指定服务器域名,可以将请求发往同一台服务器的不同站点)。1.1版本基本完善了HTTP协议,并且一直使用至今仍然是目前最流行的版本。
SPDY
于2009年由谷歌研发,使用多种新特性提高HTTP/1.1版本效率不高的问题。作为HTTP/2版本草案,在HTTP/2发布后已停止使用。
HTTP/2
于2015年发布,基于谷歌的SPDY协议之上进行了小部分修改。主要有以下特点:
- 二进制协议(HTTP/1.1版本头信息使用文本格式,数据体可以是文本或二进制格式,而HTTP/2版本则全部使用二进制格式,方便将来扩展)。
- 多工传输(复用TCP连接,双向实时通信,客户端服务器可同时发送多个请求和响应,并且不需要按照请求顺序回应,避免队头阻塞问题)。
- 头信息压缩(HTTP协议是无状态的,因此很多请求都需要带上Cookie、User Agent等重复字段,影响效率。HTTP/2使用gzip、compress等算法压缩头信息后,并且在客户端和服务器都维护一张头信息表,记录这些字段,从而提高速度)。
SSL/TLS
由于HTTP通信是全明文传输的,很多敏感信息容易被窃取。网景公司(Netspace),发明了SSL协议,用于对HTTP传输的内容进行安全加密。后来互联网标准化组织IETF将SSL推广并重新命名为TLS协议,所以SSL和TLS基本是一个东西。
HTTPS
HTTPS = HTTP + SSL/TLS,可进行加密传输、身份认证,默认443端口,需要使用CA证书,免费证书较少,需交费。HTTPS有以下几个特点: (1) 所有信息都是加密传播,黑客无法窃听。 (2) 具有校验机制,一旦被篡改,通信双方会立刻发现。 (3) 配备身份证书,防止身份被冒充。
QUIC
由谷歌制定的基于UDP的一种传输层协议,QUIC协议集成了TCP可靠传输机制、TLS安全加密、HTTP /2 多路并发流量复用技术。
协议特点
由于目前HTTP/2还没有广泛使用,HTTP/1.1仍旧是目前使用最广泛的版本,所以后面主要介绍HTTP/1.1版本的基本知识。没有特指的情况下HTTP即为HTTP/1.1版本。
HTTP的主要特点有以下几点:
- 基于TCP协议:HTTP协议目的是规定客户端和服务端数据传输的格式和数据交互行为,并不负责数据传输的细节。底层是基于TCP实现的。
- 无状态连接:HTTP协议本身不对请求和响应之间的通信状态进行保存。
- 多次请求:由于管道机制可实现一次TCP连接同时多个HTTP请求。客户端请求服务器时先响应HTML,再请求加载CSS,JS,图片等资源。
- 持久连接:当TCP连接建立后,只要任意一端没有明确提出断开连接,则保持TCP连接状态。减少TCP重复建立和断开的开销及服务器端的负载。
- 使用Cookie和Session机制管理状态:为了实现保存通信状态,引入了Cookie和Session技术。比如用户登录网站跳转到其他页面能够保存用户状态,而不需要重新登录。
- 全明文传输: 报文数据不加密(这一方面从某种意义上也方便了开发人员调试bug),敏感信息易泄露。可通过在代码上使用SSL/TLS协议改造系统,加密请求响应报文,需调试可将报文解密后保存到日志中进行问题排查。
- 内容编码: 由于某些报文的内容过大,因此在传输时,为了减少传输的时间,会采取一些压缩的措施。
- 范围请求: 当客户端请求的数据内容过大时,比如请求一张很大的图片,会发现有时候图片是一块一块加载的。这就是因为设置了http请求的长度,这样就可以分块的加载资源文件。在请求报文中使用Range属性,在响应报文中使用Content-Type属性都可以指定一定字节范围的http请求。
- 多部分对象集合: 报文传输的内容,不仅仅是一些字符串,还有可能是一些图片,字符,音乐二进制等混杂的内容。这就需要使用多部分对象集合,multipart。默认的情况下form使用的编码格式是:applicatin/x-www-form-urlencoded,这种编码格式会把所有的内容进行编码,不适合上传文件这种情况。multipart/form-data 会以控件为基准,编码form中的内容。application/x-www-form-urlencoded 会把form中的内容编码成键值对的形式。
HTTP报文
HTTP报文可以分为请求报文、响应报文。每个报文又包含三个部分首行、头部和主体。报文主体可有可无。
GET www.baidu.com HTTP/1.1
请求报文的首行叫请求行,包括请求方法、URL和HTTP版本。
HTTP/1.1 200 OK
响应报文的首行叫状态行,包括HTTP版本,状态码和简短原因,其中原因可有可无。
头部的各种协议字段通过键值对来保存,主体保存具体内容。首行、头部和主体以及头部的各项字段用回车换行(\r\n)分割,另外头部和主体之间多一个空行,也就是有两个连续的回车换行。
请求方法
请求方法是客户端用来告知服务端其操作意图的一个命令。常用的主要有GET、POST方法。其他方法不常用了解一下即可。下面是几种方法的说明:
- GET: 用于获取资源。
- POST: 用于传输实体主体。
- PUT:用于传输文件。PUT方法用来传输文件。类似FTP协议,文件内容包含在请求报文的实体中,然后请求保存到URL指定的服务器位置。
- HEAD:获取报文首部。HEAD方法类似GET方法,但是不同的是HEAD方法不要求返回数据。用于确认URI的有效性及资源更新时间等。
- DELETE:用于删除文件。DELETE方法用来删除文件,是与PUT相反的方法。DELETE是要求返回URL指定的资源。
- OPTIONS: 用于询问服务器支持的请求方法。OPTIONS 方法用来查询针对请求 URI 指定的资源支持的方法。有些服务器为了安全考虑会将PUT、DELETE方法禁用,这时可以先用OPTIONS查询支持的方法。
- TRACE:追踪路径。TRACE方法是让Web服务器将之前的请求通信环回给客户端的方法。这个方法并不常用。
- CONNECT:要求用隧道协议连接代理。CONNECT方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行TCP通信。主要使用SSL/TLS协议对通信内容加密后传输。
响应状态码
状态码是服务器用来告知客户端处理请求的结果。凭借状态码用户可以知道服务器是请求处理成功、失败或者是被转发;这样出现了错误也好定位。状态码是由3位数字加原因短语组成。3位数字中的第一位是用来指定状态的类别。共有5种类型: 状态码一共有60多种,经常使用的大概就是16种,其中加粗为最常见的情况:
- 200: OK 表示请求处理成功。
- 204: No Content 表示请求处理成功,但没有数据实体返回。
- 206: Partial Content 表示客户端指定请求范围,服务器成功执行了这部分的GET请求。响应报文中包含由请求头Content-Range指定范围的实体内容。
- 301: Moved Permanently 代表永久性定向。该状态码表示请求的资源已经被分配了新的URL,以后应该使用资源现在指定的URL。也就是说如果已经把资源对应的URL保存为书签了,这是应该按照Location首部字段提示的URL重新保存。
- 302: Found 代表临时重定向。该状态码表示请求的资源已经被分配了新的URL,但是和301的区别是302代表的不是永久性的移动,只是临时的。就是说这个URL还可能会发生改变。如果保存成书签了也不会更新。
- 303: See Other 和302的区别是303明确规定客户端应当使用GET方法。当 301、302、303 响应状态码返回时,几乎所有的浏览器都会把 POST 改成 GET,并删除请求报文内的主体,之后请求会自动再次 发送。301、302 标准是禁止将 POST 方法改变成 GET 方法的,但实际使 用时大家都会这么做。
- 304: Not Modified 表示客户端发送附带条件请求时,服务器端允许请求访问资源,但是没有满足条件。304状态码返回时不包含任何数据实体。304虽然被划分在3XX中但是和重定向没有关系。
- 307: Temporary Redirect 临时重定向,与302 Found相同,但是302会把POST改成GET,而307就不会。
- 400: Bad Request 表示请求报文中存在语法错误。需要修改后再次发送。
- 401: Unauthorized 表示发生的请求需要有通过HTTP认证的认证信息。
- 403: Forbidden 表示请求访问资源被拒绝了。没有获得服务器的访问权限,IP被禁止等。
- 404: Not Found 表示请求的资源在服务器上找不到。当然也可以在服务器拒绝请求且不想说明理由时使用。
- 408: Request Timeout 表示客户端请求超时。就是在客户端和服务器建立连接后服务器在一定时间内没有收到客户端的请求。
- 500: Internal Server Error 表明服务器端在执行请求时发生了错误,很有可能是服务端程序的Bug或者临时故障。
- 503: Service Unavaliable 表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。如果事先得知解除以上状况需要的时间,最好写入Retry-After字段再返回给客户端。
- 504: Gateway Timeout 表示网关超时,是代理服务器等待应用服务器响应时的超时,和408 Request Timeout的却别就是504是服务器的原因而不是客户端的原因。
不少返回的状态码响应都是错误的,但是用户可能察觉不到这点。 比如 Web 应用程序内部发生错误,状态码依然返回 200 OK,这种 情况也经常遇到。这时可查看相近的几次请求信息。
更多状态码的详细介绍请参考: http://tool.oschina.net/commons?type=5
HTTP首部字段
HTTP首部字段是构成HTTP报文最重要的元素之一。在客户端与服务端之前进行信息传递的时候请求和响应都会使用首部字段,会传递一些重要的元信息。首部字段是以键值对的形式存在的。包含报文的主体大小、语言、认证信息等。HTTP首部字段包含4种类型:
- 通用首部字段(General Header Fields) 代表请求报文和响应报文都会使用的字段。
- 请求首部字段(Request Header Fields) 是客户端向服务端发送请求时使用的首部字段。包含请求的附加内容、客户端信息、响应内容相关优先级等信息。
- 响应首部字段(Response Header Fields) 是服务端向客户端返回响应时使用的首部字段,包含响应的附加内容,可能也会要求客户端附加额外的内容信息。
- 实体首部字段(Entity Header Fields) 是针对请求报文和响应报文的实体部分使用的首部。包含资源内容更新时间等和实体有关的信息。
其他首部字段Cookie、Set-Cookie、Content-Disposition、Connection、Keep-Alive、Proxy-Authenticate、Proxy-Authorization、Trailer、TE、Transfer-Encoding、Upgrade etc...也很常用,关于首部字段的细节请参考《图解HTTP》或者《HTTP权威指南》的首部字段部分。
常见头部字段说明
- Accept: Accept请求报头域用于指定客户端接受哪些类型的信息。e.g. Accept:text/html,表明客户端希望接受html文本。
- Accept-Charset: Accept-Charset请求报头域用于指定客户端接受的字符集。
- Accept-Encoding: 客户端用于指定可接受的内容编码。
- Authorization: Authorization请求报头域主要用于证明客户端有权查看某个资源。
- User-Agent: 请求报头域允许客户端将它的操作系统、浏览器和其它属性告诉服务器。
- Location: 重定向地址。
- Server: 服务器用来处理请求的软件信息。
- Content-Encoding: 响应报文采用何种编码格式传输正文。主要的编码方式有gzip,compress,deflate,identity。
- Content-Language: 实体报头域描述了资源所用的自然语言。
- Content-Length: 实体正文的长度,以字节方式存储的十进制数字来表示。
- Content-Type: 响应报文的实体正文的媒体类型
相关概念介绍
与HTTP协议关联比较密切的一些概念简介:
IP协议: 位于网络层,用于计算机之间的通信。主要实现两个基本功能:寻址和分段。IP可以根据数据包包头中包括的目的地址将数据包传送到目的地址,在此过程中IP负责选择传送的道路,这种选择道路称为路由功能。
TCP协议: 位于传输层,用于应用程序之间的通信。采用“三次握手”和“四次挥手”机制建立可靠性连接。比如快递送货,IP协议相当于填写快递单号的规则以及如何根据快递单信息找到客户。TCP协议相当于送货的快递员,先打电话确认信息,再将快递送过去,最后由客户签收。
DNS协议: 用于域名解析,将域名转换为IP地址。
URI/URL:
- URL(统一资源定位符):表示资源的地点,具体指向(门牌号)。
- URI(统一资源标识符):用字符串标识某些互联网资源(该门牌号的地方具体有什么资源)。
- URL是URI的子集。
媒体类型: 互联网上有数千种不同的数据类型,http给每种需要通过http传输的对象都打上了MIME类型(MIME type)的数据格式标签。媒体类型自身实际上包含两部分。第一部分(斜线前)是_顶级媒体类型_,这部分描述了通用的类型信息以及常用处理规则。常见的顶级类型有:application,image,text,video和multipart。第二部分是 _子类型_,描述一个非常具体的数据格式。常见的媒体类型有:
- text/html: HTML格式的文本文档。
- text/plain: 普通的ASCII文本文档。
- text/xml: XML格式。
- image/png、image/jpeg、image/gif:图片类型。
- application/xml: XML数据格式
- application/json: JSON数据格式
- application/x-www-form-urlencoded: form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)。
- multipart/form-data: 表单中进行文件上传时,需要使用该格式。
更多的文件格式及对应的媒体类型信息请参考:http://tool.oschina.net/commons
一次完整的浏览器请求响应流程
当我们在浏览器地址栏输入www.baidu.com回车后。这一瞬间发生的请求过程是这样的:
- 使用DNS协议对www.baidu.com域名进行解析,得到对应的IP地址。
- 然后通过IP协议根据IP地址找到目标服务器。
- 通过TCP协议发起三次握手建立TCP连接。
- 通过TCP连接通信,浏览器发起HTTP请求。
- 服务器处理请求,浏览器得到响应报文包含HTML代码。
- 浏览器解析HTML代码,再发起请求去获取HTML中需要的CSS、JS、图片等资源。
- 浏览器对页面进行渲染并呈现给用户。
常见问题
GET和POST区别
- GET方法只用来获取资源,不会对资源状态进行修改;而POST方法用来传输实体对象,可能会对资源进行修改。
- GET请求参数会放在URL上,使用?符号进行分割,参数之间使用&符号连接,并且因为URL长度会根据不同浏览器有不同长度的限制;而POST请求参数会放到请求主体中,没有长度限制。
- GET请求参数在URL可直接查看,因此主要用于不敏感数据的快速查询;而POST数据放在实体中相对私密一些,主要可用于资源的增删改等操作。
- GET请求会被浏览器主动缓存,而POST不会,除非手动设置。
- 对参数的数据类型,GET只接受ASCII字符,而POST没有限制编码。
Cookie和Session区别
Cookie和Session都是为了保存客户端和服务端之间的交互状态,实现机制不同,各有优缺点。首先一个最大的区别就是Cookie是保存在客户端而Session就保存在服务端的。Cookie是客户端请求服务端时服务器会将一些信息以键值对的形式返回给客户端,保存在浏览器中,交互的时候可以加上这些Cookie值。用Cookie就可以方便的做一些缓存。Cookie的缺点是大小和数量都有限制;Cookie是存在客户端的可能被禁用、删除、篡改,是不安全的;Cookie如果很大,每次要请求都要带上,这样就影响了传输效率。Session是基于Cookie来实现的,不同的是Session本身存在于服务端,但是每次传输的时候不会传输数据,只是把代表一个客户端的唯一ID(通常是JSESSIONID)写在客户端的Cookie中,这样每次传输这个ID就可以了。Session的优势就是传输数据量小,比较安全。但是Session也有缺点,就是如果Session不做特殊的处理容易失效、过期、丢失或者Session过多导致服务器内存溢出,并且要实现一个稳定可用安全的分布式Session框架也是有一定复杂度的。在实际使用中就要结合Cookie和Session的优缺点针对不同的问题来设计解决方案。
参考资料
- 上野宣.《图解HTTP》.人民邮电出版社.2013-1
- 韩路彪.《看透Spring MVC源代码分析与实践》.机械工业出版社.2015-11
- 阮一峰HTTP协议入门
- 理解HTTP协议
- HTTP各版本区别
- 百度百科-IP协议
- 一次完整的浏览器请求过程
- HTTP协议之媒体类型
- HTTP协议详解