HTTP概述

2021-12-17  本文已影响0人  jxiang112

HTTP——超级文本传输协议,用于传输超媒体文档(如Html)的应用层协议,典型的应用场景是浏览器网页、API接口服务等,它可以传输文本、图片、文件、视频等。

HTTP版本简介

HTTP 0.9
该版本只有一个GET命令,协议规定服务器只能响应HTML格式的字符串,不能响应别的格式,服务器发送完毕就关闭TCP连接。虽然这一版本很简单,但是作为一个原型,奠定了Web服务的可行性。
HTTP 1.0
主要增加以下内容:

HTTP协议报文格式

HTTP请求和响应的协议报文格式是有点差别的,下面分别分开介绍:

HTTP请求协议报文格式

image

Charles抓包内容如下:

GET /kd_face/nMl9ssowtibXiaiajOk17ibqFiau1N5PKEstSxfLadEkKbwE/200 HTTP/1.1
Host: p.qpic.cn
User-Agent: Mozilla/5.0 (Linux; U; Android 11; zh-cn; M2007J17C Build/RKQ1.200826.002) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/12.1 Mobile Safari/537.36 X5Lite/052151 QbInfoApp GDTTangramMobSDK/8.400 GDTMobSDK/8.400
Q-SID: 1639042205
Accept: image/sharpp,image/*,*/*;q=0.8
Accept-Encoding: gzip, deflate

请求协议报文格式分四大部分:
1、请求行:

2、请求头部:
请求头部是一系列key:value\r\n,具体的将在下面的内容进行讲解
3、空行:
请求头部后面必须跟一个空行(\r\n)
4、请求内容:
请求内容是传递给服务器的数据,GET方法无请求内容

HTTP响应协议报文格式

image

Charles抓包的响应内容如下:

HTTP/1.1 200 OK
Server: ImgHttp3.0.0
Vary: Accept,Origin
Content-Type: image/jpeg
Content-Length: 4609
Last-Modified: Wed, 01 Dec 2021 11:03:10 GMT
Cache-Control: max-age=2592000
X-Delay: 329 us
X-Info: real data
X-BCheck: 0_1
X-Cpt: filename=0
User-ReturnCode: 0
X-DataSrc: 2
X-ReqGue: 0
Size: 4609
chid: 0
fid: 0
Proxy-Connection: Keep-alive

ÿØÿà

响应协议报文格式分四大部分:
1、状态行:

HTTP协议解析

以下将针对HTTP协议报文格式中各个重要部分进行讲解,包括响应状态行中的状态码、HTTP头部、HTTP头部缓存、HTTP头部状态管理、HTTP头部编码和解码、HTTP头部身份认证、HTTP长短连接、HTTP头部代理其及原理等。

HTTP请求方法

幂等:连续一次或多次请求得到结果一样(无副作用)
GET: GET方法请求指定资源的表示形式,使用GET的请求应该只检索数据,是幂等,可缓存。一般定位为获取资源,而不更改服务端资源和状态,所以不论请求多少次结果都是一样的。GET方法可以提交参数(一般用作检索参数),会被附加到URL的后面,如:http://localhost/test?param1=value1&param2=value2
HEAD: HEAD方法与GET类似,只是返回的响应中没有具体内容,是幂等,可缓存。用于获取头部,而且这些头部与使用GET方法请求时返回的头部一致。一般使用场景是:在下载一个大文件前,先获取获取头部的信息如大小(Content-length)再决定是否要下载,以此节约带宽资源。
POST: POST方法提交实体到指定的资源,一般提交的实体用于会引起资源的变化或产生副作用(添加、修改资源、出现异常等),连续一次或多次调用同一个POST可能带来额外的影响,比如多次提交订单,得到结果是不一样的,所有它是非幂等,且不缓存。POST提交的实体内容不会拼接在URL后面,而是填充协议中的body部分,所以相比GET方式而已长度不受限制、更为安全
PUT: 使用请求中的负载创建或者替换目标资源。与POST相似,但PUT是幂等的,即连续一次或多次调用同一个PUT得到的结果是一样的。可以理解PUT为覆盖,无则添加,有则覆盖。如果提交的PUT请求目标资源不存在,且服务端成功创建了,则服务端返回201表示客户端请求的资源已创建;如果提交的资源已存在,并且依照请求中封装的表现形式成功进行了更新,那么服务器必须返回200(ok)或204(No Content)来表示请求成功完成。
PATCH: PATCH属于局部修改,非幂等,不可缓存。常见的比如userInfo(有id、用户名、年龄等),有的界面只修改年龄,此时使用PATCH只需要提交年龄的参数到服务端,服务端只修改接收到的参数,这样不用提交整个userInfo。PUT也是更改,区别是PUT是需要提交真个实体去修改,比如要提交完整的userInfo实体,如果userInfo中其他字段为空,那么服务端的userInfo的相关字段会被清空。
DELETE: 用于删除指定的资源,是幂等
CONNECT: 用于建立到目标资源标识的服务器的隧道,即建立客户端与请求资源之间的双向通信
OPTIONS: 用于获取目的资源所支持的通信选项。没有请求实体、不可缓存,它一般用于检索服务器支持的请求方法
TRACE: 实现沿通向目标资源的路径的消息环回,提供一种实用的debug机制。请求的最终接收者应当原样返回它收到的消息,除了一下字段部分,作为一个Content-Type为message/http的200(OK)响应的消息的主体(body)返回给客户端。是幂等且不可缓存

HTTP状态码

HTTP状态码表示当前响应的状态,由三个数字组成,第一位数字表示响应的类别,有五大类别:
1xx: 信息状态码,表示服务端已收到请求,需要请求在继续执行操作
2xx: 成功状态码,表示请求正常处理完成
3xx: 重定向状态码,表示客户端需要进一步的操作以完成请求
4xx: 客户端错误状态码,表示客户端请求有语法错误或无法完成请求
5xx: 服务端错误状态码,表示服务端处理请求时出现错误
常见的错误码如下:

状态码 状态码描述信息 描述
200 OK 请求已成功,请求所希望的响应头和数据体将随此响应返回
202 Accepted 已接收,请求已接收,但未完成处理
206 Partial Content 部分内容,服务器成功处理部分请求
301 Moved Parmanently 永久移动,请求的资源已被永久移动到新的URI,返回信息包含新的URI
302 Found 临时移动,与301相似,但资源只是临时移动,客户端应该继续使用原URI
400 Bad Request 客户端请求语法错误,服务器无法理解
401 Unauthorized 未认证,请求要求用户的身份认证
403 Forbidden 服务器理解客户端请求,但拒绝执行此请求
404 Not Found 服务器无法根据客户端的请求找到对应资源(网页或者接口)
500 Internal Server Error 服务器处理请求出现内部错误,无法完成请求
502 Bad Gateway 充当网关或代理的服务器,从远端服务器接收到了一个无效的请求,一般是网关或端口错误

更多状态码请详见:HTTP状态码

HTTP头部

HTTP协议中的头部是key/value的形式,它们有的为请求服务,有的为响应服务,有的为实体服务,基于此,我们将一下常用头发的进行划分:

通用头部

这部分的头部可用于请求和响应的头部,但不可以是应用于实体的头部

字段名 说明
Cache-Control 控制缓存的行为,将在缓存部分进行讲解
Connection 决定当前事务完成之后,是否关闭连接(即决定连接是长连接还是短连接)。=keep-alive表示连接是之久的,完成事务后不会关闭连接,它是HTTP/1.1的默认值;=close表示短连接,完成事务后关闭连接,是HTTP/1.0的默认值。Connection不能与HTTP/2一起使用
Date 报文创建的日期和时间,格式:<day-name>,<day>,<month>,<year> <hour>:<minute>:<second> GMT。例如:Wed, 21 Oct 2015 07:28:00 GMT

请求报文头部

这部分主要用于请求时的头部

字段名 说明
Accept 请求头用来告知客户端可以处理的内容类型,格式:MINE_TYPE/MINE_SUB_TYPE[;q=权重因子,代表优先级],如:/、image/*、text/html, application/xhtml+xml;q=0.9。服务器会根据内容协商机制(下文会进行说明)从诸多选项中选择合适的一项进行应用,并使用Content-Type应答头通知客户端它的选择
Accept-Charset 请求头用来告知服务端客户端可以处理的字符集类型,服务端会截止内容协商机制(下文进行说明)从诸多选项中选择一项合适的进行处理,并使用Content-Type响应头告知客户端它的选择。 例如:Accept-Charset:utf-8,iso-8859-1;q=0.5, *;q=0.1
Accept-Encoding 将客户端能够理解的内容编码方式(某种压缩算法)告知服务端,服务端通过内容协商机制,选择一个客户端提议的方式,并使用响应头Content-Encoding通知客户端它的选择。值有:gzip、compress、deflate、br、identity、、;q=权重因子。例如:Accept-Encoding: gzip, compress;q=0.1,;q=0.2
Accept-Language 声明客户端可以理解的自然语言以及优先选择的区域方言。服务端借助内容协商机制从诸多选项中选择一项合适的进行应用,并使用Content-Language响应头通知客户端它的选择。值有:<language>(含2-3个字符的字符串表示语言或者完整的语言标签,可以使用-来表明方言,如en-US)、<*>(任意语言)、<;q=权重因子>。例如:Accept-Language: en-US, *;q=0.1
Authorization 被用于服务端验证用户代理身份的凭证,通常会在服务器返回401状态码以及WWW-Authenticate头之后,在后续的请求中发生此消息头。格式:Authorization: <验证类型> <凭证>。验证类型:BASIC、DIGEST、SSL等。例如:Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
Expect 包含一个期望条件,表示服务器只有满足此期望条件的情况下才能妥善地处理请求。 值只有:100-continue,对此服务端可以响应:如果服务端可以满足期望条件,响应100状态码,告知客户端继续发送消息;如果服务器不能满足期望条件,响应417告知客户端请求不能得到满足。应用场景一般是客户端请求的内容过大,如上传大文件,可以先发送一个请求含Expect和Content-Length,在得到100的响应之后,再继续发送内容。
From 邮箱地址,一般用于出现问题服务端或者管理员联系到请求发送者
Host 指明请求将要发送到的服务器主机名和端口号,如果没有端口号,http默认使用80,https默认使用443。HTTP/1.1中必须包含一个Host字段,如果HTTP/1.1 缺少或超过一个Host字段,可能会收到400
If-Match 请求首部 If-Match 的使用表示这是一个条件请求。在请求方法为 GETHEAD 的情况下,服务器仅在请求的资源满足此首部列出的 ETag值时才会返回资源。而对于 PUT 或其他非安全方法来说,只有在满足条件的情况下才可以将资源上传。ETag 之间的比较使用的是强比较算法,即只有在每一个字节都相同的情况下,才可以认为两个文件是相同的。在 ETag 前面添加 W/ 前缀表示可以采用相对宽松的算法。以下是两个常见的应用场景:* 对于 GETHEAD 方法,搭配 Range首部使用,可以用来保证新请求的范围与之前请求的范围是对同一份资源的请求。如果 ETag 无法匹配,那么需要返回 416(Range Not Satisfiable,范围请求无法满足) 响应。* 对于其他方法来说,尤其是 PUT, If-Match 首部可以用来避免更新丢失问题。它可以用来检测用户想要上传的不会覆盖获取原始资源之后做出的更新。如果请求的条件不满足,那么需要返回 412 (Precondition Failed,先决条件失败) 响应。例子:If-Match: "bfc13a64729c4290ef5b2c2730249c88ca92d82d" 或 If-Match: W/"67ab43", "54ed21", "7892dd" 或 If-Match: *
If-Modified-Since If-Modified-Since 是一个条件式请求首部,服务器只在所请求的资源在给定的日期时间之后对内容进行过修改的情况下才会将资源返回,状态码为 200 。如果请求的资源从那时起未经修改,那么返回一个不带有消息主体的 304 响应,而在 Last-Modified 首部中会带有上次修改时间。 不同于 If-Unmodified-Since, If-Modified-Since 只可以用在 GETHEAD 请求中。当与 If-None-Match 一同出现时,它(If-Modified-Since)会被忽略掉,除非服务器不支持 If-None-Match。最常见的应用场景是来更新没有特定 ETag 标签的缓存实体。语法:If-Modified-Since: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT。例子:If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT
If-None-Match If-None-Match 是一个条件式请求首部。对于 GETGETHEAD 请求方法来说,当且仅当服务器上没有任何资源的 ETag 属性值与这个首部中列出的相匹配的时候,服务器端才会返回所请求的资源,响应码为 200 。对于其他方法来说,当且仅当最终确认没有已存在的资源的 ETag 属性值与这个首部中所列出的相匹配的时候,才会对请求进行相应的处理。对于 GETHEAD 方法来说,当验证失败的时候,服务器端必须返回响应码 304 (Not Modified,未改变)。对于能够引发服务器状态改变的方法,则返回 412 (Precondition Failed,前置条件失败)。需要注意的是,服务器端在生成状态码为 304 的响应的时候,必须同时生成以下会存在于对应的 200 响应中的首部:Cache-Control、Content-Location、Date、ETag、Expires 和 Vary 。ETag 属性之间的比较采用的是弱比较算法,即两个文件除了每个字节都相同外,内容一致也可以认为是相同的。例如,如果两个页面仅仅在页脚的生成时间有所不同,就可以认为二者是相同的。当与 If-Modified-Since 一同使用的时候,If-None-Match 优先级更高(假如服务器支持的话)。以下是两个常见的应用场景:* 采用 GETHEAD 方法,来更新拥有特定的ETag 属性值的缓存 * 采用其他方法,尤其是 PUT,将 If-None-Match used 的值设置为 * ,用来生成事先并不知道是否存在的文件,可以确保先前并没有进行过类似的上传操作,防止之前操作数据的丢失。这个问题属于更新丢失问题的一种。语法:If-None-Match: <etag_value>, <etag_value>, … 或 If-None-Match: *
If-Range If-Range HTTP 请求头字段用来使得 Range 头字段在一定条件下起作用:当字段值中的条件得到满足时,Range 头字段才会起作用,同时服务器回复206 部分内容状态码,以及Range 头字段请求的相应部分;如果字段值中的条件没有得到满足,服务器将会返回 200 OK 状态码,并返回完整的请求资源。字段值中既可以用 Last-Modified 时间值用作验证,也可以用ETag标记作为验证,但不能将两者同时使用。If-Range 头字段通常用于断点续传的下载过程中,用来自从上次中断后,确保下载的资源没有发生改变。语法:If-Range: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT 或 If-Range: <etag>
If-Unmodified-Since HTTP协议中的 If-Unmodified-Since 消息头用于请求之中,使得当前请求成为条件式请求:只有当资源在指定的时间之后没有进行过修改的情况下,服务器才会返回请求的资源,或是接受 POST 或其他 non-safe 方法的请求。如果所请求的资源在指定的时间之后发生了修改,那么会返回 412 (Precondition Failed) 错误。常见的应用场景有两种:* 与 non-safe 方法如 POST 搭配使用,可以用来优化并发控制,例如在某些wiki应用中的做法:假如在原始副本获取之后,服务器上所存储的文档已经被修改,那么对其作出的编辑会被拒绝提交。* 与含有 If-Range 消息头的范围请求搭配使用,用来确保新的请求片段来自于未经修改的文档。语法:If-Unmodified-Since: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT
Proxy-Authorization Proxy-Authorization 是一个请求首部,其中包含了用户代理提供给代理服务器的用于身份验证的凭证。这个首部通常是在服务器返回了 407 Proxy Authentication Required 响应状态码及 Proxy-Authenticate 首部后发送的。语法:Proxy-Authorization: <type> <credentials>。
Range The Range 是一个请求首部,告知服务器返回文件的哪一部分。在一个 Range 首部中,可以一次性请求多个部分,服务器会以 multipart 文件的形式将其返回。如果服务器返回的是范围响应,需要使用 206 Partial Content 状态码。假如所请求的范围不合法,那么服务器会返回 416 Range Not Satisfiable 状态码,表示客户端错误。服务器允许忽略 Range 首部,从而返回整个文件,状态码用 200 。语法:Range: <unit>=<range-start>-<range-end>, <range-start>-<range-end>...。unit: 范围所采用的单位,通常是字节(bytes);range-start:一个整数,表示在特定单位下,范围的起始值;range-end:一个整数,表示在特定单位下,范围的结束值。这个值是可选的,如果不存在,表示此范围一直延伸到文档结束。例子:Range: bytes=200-1000, 2000-6576, 19000-
Referer Referer 请求头包含了当前请求页面的来源页面的地址,即表示当前页面是通过此来源页面里的链接进入的。服务端一般使用 Referer 请求头识别访问来源,可能会以此进行统计分析、日志记录以及缓存优化等。语法:Referer: <url>。例如:Referer: https://developer.mozilla.org/en-US/docs/Web/JavaScript
TE **TE** 请求型头部用来指定用户代理希望使用的传输编码类型。(可以将其非正式称为 Accept-Transfer-Encoding, 这个名称显得更直观一些)。可以参考 Transfer-Encoding 来获取更多关于传输编码的细节信息。值得注意的是, 支持 HTTP/1.1 协议的接收方一定可以处理 chunked 传输编码请求,所以没有必要一定在 TE 首部指定“chunked”关键字。然而,如果客户端将要接收编码在chunked包体里面的"trailer"信息的时候,主动指定该头部将会非常有用。
User-Agent User-Agent 首部包含了一个特征字符串,用来让网络协议的对端来识别发起请求的用户代理软件的应用类型、操作系统、软件开发商以及版本号。语法:User-Agent: <product> / <product-version> <comment>。例如:Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0

响应报文头部

这部分主要用于响应时的头部

字段名 说明
Accept-Ranges 服务器使用 HTTP 响应头 Accept-Ranges 标识自身支持范围请求(partial requests)。字段的具体值用于定义范围请求的单位。当浏览器发现 Accept-Ranges 头时,可以尝试继续中断了的下载,而不是重新开始。语法:Accept-Ranges: bytes 或 Accept-Ranges: none。
Age Age 消息头里包含对象在缓存代理中存贮的时长,以秒为单位。Age的值通常接近于0。表示此对象刚刚从原始服务器获取不久;其他的值则是表示代理服务器当前的系统时间与此应答中的通用头 Date 的值之差。语法:Age: <delta-seconds>(一个非负整数,表示对象在缓存代理服务器中存贮的时长,以秒为单位。)
Content-Range 在HTTP协议中,响应首部 Content-Range 显示的是一个数据片段在整个文件中的位置。语法:Content-Range: <unit> <range-start>-<range-end>/<size>(或<unit> <range-start>-<range-end>/*或<unit> /<size>)。<unit>:数据区间所采用的单位。通常是字节(byte)。<range-start>:一个整数,表示在给定单位下,区间的起始值。<range-end>:一个整数,表示在给定单位下,区间的结束值。<size>:整个文件的大小(如果大小未知则用""表示)。例如:Content-Range: bytes 200-1000/67589
ETag ETagHTTP响应头是资源的特定版本的标识符。这可以让缓存更高效,并节省带宽,因为如果内容没有改变,Web服务器不需要发送完整的响应。而如果内容发生了变化,使用ETag有助于防止资源的同时更新相互覆盖(“空中碰撞”)。如果给定URL中的资源更改,则一定要生成新的Etag值。 因此Etags类似于指纹,也可能被某些服务器用于跟踪。 比较etags能快速确定此资源是否变化,但也可能被跟踪服务器永久存留。语法:ETag: W/"<etag_value>" 或 ETag: "<etag_value>"。'W/'(大小写敏感) 表示使用弱验证器。 弱验证器很容易生成,但不利于比较。 强验证器是比较的理想选择,但很难有效地生成。 相同资源的两个弱Etag值可能语义等同,但不是每个字节都相同。<etag_value>":实体标签唯一地表示所请求的资源。 它们是位于双引号之间的ASCII字符串(如“675af34563dc-tr34”)。 没有明确指定生成ETag值的方法。 通常,使用内容的散列,最后修改时间戳的哈希值,或简单地使用版本号。 例如,MDN使用wiki内容的十六进制数字的哈希值。
Expires Expires 响应头包含日期/时间, 即在此时候之后,响应过期。无效的日期,比如 0, 代表着过去的日期,即该资源已经过期。如果在Cache-Control响应头设置了 "max-age" 或者 "s-max-age" 指令,那么 Expires 头会被忽略。语法:Expires: <http-date>。例如:Expires: Wed, 21 Oct 2015 07:28:00 GMT
Last-Modified The Last-Modified 是一个响应首部,其中包含源头服务器认定的资源做出修改的日期及时间。 它通常被用作一个验证器来判断接收到的或者存储的资源是否彼此一致。由于精确度比 ETag 要低,所以这是一个备用机制。包含有 If-Modified-SinceIf-Unmodified-Since 首部的条件请求会使用这个字段。语法:Last-Modified: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT
Location Location 首部指定的是需要将页面重新定向至的地址。一般在响应码为3xx的响应中才会有意义。发送新请求,获取Location指向的新页面所采用的方法与初始请求使用的方法以及重定向的类型相关:* 303 (See Also) 始终引致请求使用 GET 方法,而,而 307 (Temporary Redirect) 和 308 (Permanent Redirect) 则不转变初始请求中的所使用的方法;* 301 (Permanent Redirect) 和 302 (Found) 在大多数情况下不会转变初始请求中的方法,不过一些比较早的用户代理可能会引发方法的变更(所以你基本上不知道这一点)。状态码为上述之一的所有响应都会带有一个Location首部。除了重定向响应之外, 状态码为 201 (Created) 的消息也会带有Location首部。它指向的是新创建的资源的地址。语法:Location: <url>
Proxy-Authenticate The HTTP Proxy-Authenticate 是一个响应首部,指定了获取 proxy server (代理服务器)上的资源访问权限而采用的身份验证方式。代理服务器对请求进行验证,以便它进一步传递请求。Proxy-Authenticate首部需要与 407 Proxy Authentication Required 响应一起发送。
Retry-After 在HTTP协议中,响应首部 Retry-After 表示用户代理需要等待多长时间之后才能继续发送请求。这个首部主要应用于以下两种场景:* 当与 503 (Service Unavailable,当前服务不存在) 响应一起发送的时候,表示服务下线的预期时长;* 当与重定向响应一起发送的时候,比如 301 (Moved Permanently,永久迁移),表示用户代理在发送重定向请求之前需要等待的最短时间。语法:Retry-After: <http-date>(表示在此时间之后可以重新尝试。参见 Date 首部来获取HTTP协议中关于日期格式的细节信息);Retry-After: <delay-seconds>(一个非负的十进制整数,表示在重试之前需要等待的秒数)
Server Server 首部包含了处理请求的源头服务器所用到的软件相关信息。应该避免使用过长或者过于详细的描述作为 Server 的值,因为这有可能泄露服务器的内部实现细节,有利于攻击者找到或者探测已知的安全漏洞。例子:Server: Apache/2.4.1 (Unix)
Vary Vary 是一个HTTP响应头部信息,它决定了对于未来的一个请求头,应该用一个缓存的回复(response)还是向源服务器请求一个新的回复。它被服务器用来表明在 content negotiation algorithm(内容协商算法)中选择一个资源代表的时候应该使用哪些头部信息(headers).在响应状态码为 304 Not Modified 的响应中,也要设置 Vary 首部,而且要与相应的 200 OK 响应设置得一模一样。语法:Vary: *(所有的请求都被视为唯一并且非缓存的,使用Cache-Control: no-store,来实现则更适用,这样用于说明不存储该对象更加清晰。);Vary: <header-name>, <header-name>, ...(逗号分隔的一系列http头部名称,用于确定缓存是否可用。)
WWW-Authenticate HTTP WWW-Authenticate 响应头定义了使用何种验证方式去获取对资源的连接。WWW-Authenticate header通常会和一个 401 Unauthorized 的响应一同被发送。语法:WWW-Authenticate: <type> realm=<realm>

实体报文头部

这部分主要用于实体即body的头部

字段名 说明
Allow Allow 首部字段用于枚举资源所支持的 HTTP 方法的集合。若服务器返回状态码 405 Method Not Allowed,则该首部字段亦需要同时返回给客户端。如果 Allow 首部字段的值为空,说明资源不接受使用任何 HTTP 方法的请求。这是可能的,比如服务器需要临时禁止对资源的任何访问。例如:Allow: GET, POST, HEAD
Content-Encoding Content-Encoding 是一个实体消息首部,用于对特定媒体类型的数据进行压缩。当这个首部出现的时候,它的值表示消息主体进行了何种方式的内容编码转换。这个消息首部用来告知客户端应该怎样解码才能获取在 Content-Type 中标示的媒体类型内容。一般建议对数据尽可能地进行压缩,因此才有了这个消息首部的出现。不过对于特定类型的文件来说,比如jpeg图片文件,已经是进行过压缩的了。有时候再次进行额外的压缩无助于负载体积的减小,反而有可能会使其增大。语法:Content-Encoding: gzip(或compress 或deflate或identity或br)
Content-Language Content-Language 是一个 entity header (实体消息首部),用来说明访问者希望采用的语言或语言组合,这样的话用户就可以根据自己偏好的语言来定制不同的内容。举个例子,假如设置了这样一条消息首部( "Content-Language: de-DE" ),那么说明这份文件是为说德语的人提供的(当然这并不意味着文件本身就是用德语写的。比如,它可能是为说德语的人开设的英语教程的一部分,也就是用英语写的)。如果没有指明 Content-Language,那么默认地,文件内容是提供给所有语言的访问者使用的。多个语言标签也是合法的,同样的,这个首部还可以用来描述不同媒体类型的文件,而不单单局限于文本型文档。语法:Content-Language: de-DE, en-CA(多个语言标签需要用逗号隔开。每一个语言标签都是由一个或多个不区分大小写的子标签构成的,子标签之间用连字号 ("-", %x2D)隔开。通常情况下,一个语言标签是由标识一个大的语言家族的主语言子标签(例如"en" = English),以及后面可选的用来缩小语言范围使更确切的一系列子标签("en-CA" 表示在加拿大范围使用的英语的变种)构成的。)
Content-Length Content-Length 是一个实体消息首部,用来指明发送给接收方的消息主体的大小,即用十进制数字表示的八位元组的数目。语法:Content-Length: <length>
Content-Location Content-Location 首部指定的是要返回的数据的地址选项。最主要的用途是用来指定要访问的资源经过内容协商后的结果的URL。LocationContent-Location是不同的,前者(Location )指定的是一个重定向请求的目的地址(或者新创建的文件的URL),而后者( Content-Location) 指向的是可供访问的资源的直接地址,不需要进行进一步的内容协商。Location 对应的是响应,而Content-Location对应的是要返回的实体。语法:Content-Location: <url>
Content-Type Content-Type 实体头部用于指示资源的MIME类型 media type 。在响应中,Content-Type标头告诉客户端实际返回的内容的内容类型。浏览器会在某些情况下进行MIME查找,并不一定遵循此标题的值; 为了防止这种行为,可以将标题 X-Content-Type-Options 设置为 nosniff。在请求中 (如POSTPUT),客户端告诉服务器实际发送的数据类型。语法:Content-Type: text/html; charset=utf-8(或Content-Type: multipart/form-data; boundary=something)。media-type:资源或数据的 MIME type 。charset:字符编码标准。boundary:对于多部分实体,boundary 是必需的,其包括来自一组字符的1到70个字符,已知通过电子邮件网关是非常健壮的,而不是以空白结尾。它用于封装消息的多个部分的边界。

HTTP缓存

缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。当web缓存发现请求的资源已经被被存储时,它会拦截请求,返回该资源的拷贝,而不会去源服务器重新下载。这样带来的好处有:缓解服务器压力,提升性能。缓存不是永久不变的,一个资源的缓存应截止到其下一次发生变化。
缓存分为两大类:私有缓存和共享缓存。私有缓存存储的响应只能用于单独用户,常见有浏览器或其他客户端;共享缓存存储的响应可以被多个用户使用,常见的有代理服务器、CDN等。
HTTP缓存一般只能存储GET响应,对其他类型的响应无能为力。
HTTP通过以下头部实现缓存策略和验证机制:
Cache-Control: 可用于请求和响应头,是HTTP/1.1的缓存控制机制,它的值可以多个一起使用,使用逗号分隔,其值有:

Expires:响应头,代表过期具体的时间点,是HTTP/1.0的属性。与Cache-Control: max-age=xx共存时,Expires的优先级比较低
Last-Modified与If-Modified-Since:

only-if-cached:
表明客户端只接受已缓存的响应,并且不要向原始服务器检查是否有更新的拷贝

Etag与If-None-Match:

** HTTP缓存工作方式
1、客户端发起请求——》本地缓存校验——》没有缓存,向服务器发起请求,含有Cache-Control期望的缓存策略——》服务端返回内容及相互缓存头信息:Cache-Control、Etag、Last-Modified、Vary、Expires等——》客户端缓存并做出业务相关的响应
2、客户端发起请求——》本地缓存校验——》有缓存,且未过期——》客户端使用缓存内容
3、客户端发起请求——》本地缓存校验——》有缓存,但已过期——》发送请求到服务端,使用缓存中响应头的Etag(赋值给当前请求头的If-None-Match)、Last-Modified(赋值给当前请求头的If-Modified-Since)、Cache-Control、Vary等——》服务端继续缓存机制的校验——》资源内容有更新,返回200、新资源内容、新Etag、新Last-Modified、新Cache-Control、新Expired等——》客户端缓存并做出业务相关的响应
3.1、客户端发起请求——》本地缓存校验——》有缓存,但已过期——》发送请求到服务端,使用缓存中响应头的Etag(赋值给当前请求头的If-None-Match)、Last-Modified(赋值给当前请求头的If-Modified-Since)、Cache-Control、Vary等——》服务端继续缓存机制的校验——》资源内容没有更新,返回304、Etag、Last-Modified、Cache-Control、Expired等——》客户端继续使用原缓存

其中:Etag和Vary是强缓存验证,必须每个字节都相等才表示相等;Last-Modified是弱缓存验证,因为Last-Modified只能精确到秒,如果1秒之内资源进行更新了,Last-Modified是无法感知的。所以校验优先级如下:
Vary > max-age > Expires > Etag(If-None-Match) > Last-Modified(If-Modified-Since)
Vary、max-age和Expires一般在本地缓存或缓存服务器进行验证
Etag和Last-Modified一般在服务器进行验证

HTTP状态管理

HTTP协议是无状态的,但是有时需要保存用户的登录状态,所以才有了HTTP状态管理机制,HTTP的Cookie使HTTP协议记录状态成为了可能。

Cookie

HTTP Cookie是服务器发送给客户端并保存在本地的一小块数据,它会再客户端下次向同一服务器再发起请求时被携带并发送到服务器。
它的主要用于以下三个方面:

Cookie现状: Cookie曾一度被用于客户端存储数据,但随着互联网技术的发展,Cookie逐渐被淘汰。这是因为服务器指定Cookie之后,客户端的每次请求都会携带Cookie数据,会带来额外的性能开销。已被Web storage API或IndexedDB或TOKEN逐渐取代。

Cookie使用:
服务端通过Set-Cookie响应头将Cookie发送给客户端。格式:Set-Cookie: key=value[;Expires=Date Time][;Max-Age=second][;Secure][;HttpOnly][;SameSize=xxx][;Domain=xxx][;Path=xxx]

以下是服务端的响应举例:

HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry

以下是客户端请求的举例:

GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry

Session

Session代表客户端和服务端的一次会话过程。Session存储特定用户会话所需的属性和配置信息。当用户在应用程序的Web页面之间跳转时,存储在Session中的信息将不会丢失,而是在整个用户会话中一直存在。当客户端关闭会话或者Session超时时会话结束。
Session是存在在服务端端,服务器将Session数据存储在服务端,并使用SessionId与之关联,接着把SessionId返回给客户端,作为会话id,客户端将sessionId使用cookie缓存或者存在在隐藏表达或者存在在全局变量做作为下次请求的会话id传递给服务端,这样保持会话状态的持续性。
与Cookie的区别:

HTTP编码和解码

我们都知道计算机机器只能识别二进制,对应我们使用的各种字符是无法直接识别的,这就是编码和解码的用处所在:
编码:编码就是将字符根据选用的编码规范(字符集规范)通过编码方式(编码算法)处理转换为对应的二进制数值
解码:解码就是将二进制根据选用的编码规范(字符集规范)通过解码方式(解码算法)处理转换为我们能识别的字符
上述表述的涉及:二进制、编码规范(字符集规范)、编码方式、字符,这些都是什么感念?
二进制:由0和1组织的一串数字
字节:字节是计算机存储容量的计量单位(单位:B)。因为计算机只能识别0和1组成的二进制位,一个树就是1位(bit),8位就是一个字节
字符:任何一个文字或符合就是一个字符,不同的编码会导致一个字符所占的内存不同。例如:‘a’ 是一个字符,在ASCII中占1个字节,在Unicode中占4个字节。
编码规范&编码方式:

每一种编码规范都由的字库表、编码字符集(字符集)、编码方式组成
字库表:每一套编码规范不一定包含世界上所有的字符,每一套编码规范都有对应的字库表,字库表存储的是编码规范中所能显示的所有字符及其与之对应的二进制地址。
编码字符集(字符集):在一个字库表中,每个字符都有一个对应的二进制地址,而字符集就是这些地址的集合。
例如:在ASCII中,字母A在编码字符集中排第65位,编码后A的数值是0100 0001,也就是十进制65的二进制的转换结果。编码字符集是用来存储这些二进制数的,而这个二进制数既是编码字符集中的一个元素,也是字库表中字母A的地址,我们根据这个地址可以显示出字母A。

常见的编码规范有:
ASCII:是最早产生的编码规范,一共包含00000000-01111111共128个字符,可以表示阿拉伯数字、大小英文字母以及一些简单的符合。ASCII码只需要1个字节的存储空间,最高位为0,它没有特定的编码方式,直接使用地址对应的二进制数来表示。
GBK:支持国家标准ISO/IEC10646-1和国家标准GB13000-1中的全部中日韩汉字。GBK字符集中所有字符占2个字符,不论中文英文都是2个字节。没有特殊的编码方式,一般在国内,汉字较多时使用。
ISO-8859-1:收录的字符出ASCII收录的字符外,还包括西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符合。因为ISO-8858-1编码范围使用了单字节内的所有空间,在支持ISO-8859-1的系统中传输和存储其他编码的字节流都不会被抛弃。换言之,把其他任何其他编码的字节流当做ISO-8859-1编码看待都没有问题。这是个很重要的特性,Mysql数据库默认编码是Latin1就是利用这个特性。ASCII编码是一个7位的容器,ISO-8859-1是一个8位容器。ISO-8859-1只占1个字节,且Mysql数据库默认编码就是ISO-8859-1。
Unicode: 从以上几种编码规范可以看出,各种编码规范互不兼容,且只能表示自己需要的字符,于是,国家标准化组织ISO决定制定一套全世界通用的编码规范Unicode。Unicode包含了全世界所有的字符,最多可以保存4个字节容量的字符。也就是说,要区分每个字符,每个字符需要的地址需要4个字节。这是十分浪费的存储空间,于是出有了:UTF-8、UTF-16、UTF-32等的编码方式。使用最广泛的是UTF-8.

我们分别看三个从一个字节到三个字节的UTF-8编码例子:

实际字符 Unicode字库序号16进制 Unicode字库序号的二进制 UTF-8编码后的二进制 UTF-编码后的16进制
& 0024 010 0100 0010 0100 24
¢ 00A2 000 1010 0010 1100 0010 1010 0010 C2A2
20AC 0010 0000 1010 1100 1110 0010 1000 0010 1010 1100 E282AC

HTTP身份认证

HTTP请求时,如果服务器需要进行身份认证,会返回401状态告知客户端需要发送认证信息进行认证,此时客户端将认证信息填充在头部的Authorization中。Authorization: type(认证类型) authinfo(认证信息)
场景的认证类型有:
BASIC:基本认证,它是一种比较简单的HTTP认证方式,客户端通过明文(Base64编码格式)传输认证信息(如用户名和密码)到服务端进行认证,通常需要配合HTTPS来保证信息传输的安全。其认证流程如下图所示:

image
Basic认证缺点:

DIGEST:摘要认证。而弥补BASIC认证存在的缺点,从HTTP/1.1开始使用DIGEST认证,它不会像BASIC认证那样方式明文,其认证流程如下图所示:

image

SSL客户端认证: 借由HTTPS的客户端证书完成认证的方式。凭借客户端证书认证,服务器可以确认访问是否来自自己登陆的客户端。
FormBase认证: 基于表单认证,它并不是HTTP协议中的定义的,而是使用有Web应用程序各自实现基于表单的认证方式,通过Cookie和Session的方式来保持用户的状态。

HTTP长连接和短连接

HTTP协议是基于请求/响应的模式,因此只要服务器响应了,本次HTTP请求就结束了。基于历史和技术发展,HTTP/1.0默认采用短连接,即客户端和服务端没进行一次HTTP操作,就建立一次连接,结束就关闭;HTTP/1.1开始,默认使用长连接,用于连接复用,较少建立连接和关闭连接的性能损耗。
HTTP请求头使用Connection来表示当前请求使用的是长连接还是短连接,Connection的值由:

短连接:每次请求都会建立新的连接,结束则关闭。优势:每次连接都是新建的,所以只要能建立连接,数据基本上都能送达;缺陷:每次都需要重新建立连接,每次连接都需要经过TCP三次握手,使得相对耗时,降低了性能,而且每次都新建连接,但TCP连接数是有限制的,如果同时存在很多请求时,就会出现无法完成正常工作。

长连接:每次请求不会立马关闭连接,而是空闲一段时间(这个空闲时间可以通过服务器返回的keep-alive协议头来指定),用于连接复用,这样无需建立新的连接。优势:多次请求会复用连接,所有减少了连接和关闭的开销,并使多次数据传输的总耗时减少。缺陷:因为空闲一段时间才可能关闭,所有需要消耗一些CPU资源;还有就是需要花费额外的开销来维护连接是否可用(网络异常、服务器异常等)。长连接维持一个连接是否可用可以使用:利用TCP自身保活机制实现,保活机制会定时发送探测报文来识别对方是否可达,一般默认定时时间间隔2小时,可以在系统层面调整这个定时间隔;上次应用主动定时发送一个心跳包,探测是否能成功送达另一端,可达则继续保持连接,不可达断开连接。

HTTP代理

代理即是客户端也是服务端,它将客户端的请求(可能会进行一些额外的处理)转发到服务端,再将服务端的响应(可能会进行额外处理)返回给客户端。流程是:客户端发出请求——》代理将客户端的请求包装并向服务端发出请求——》服务器将响应返回给代理——》代理将服务端的响应包装后返回给客户端——》客户端收到代理的响应。
代理的作用:

HTTP内容协商

内容协商指的是客户端和服务端就响应内容进行交涉,然后提供给客户端最为适合的内容。内容协商以响应内容的语言、字符集、编码方式等作为判断的基准。

内容协商方式

客户端驱动:客户端发起请求,服务端发送可选项,客户端做出选择在发送第二次请求。这种需要至少两次的请求,增加了时延。
服务端驱动:客户端发起请求,并在头部提供可选项供服务端决定选择那一项。至少一次请求即可完成,相比客户端驱动要快,HTTP提供的q(权重,选项优先级)进行近似匹配。如果客户端请求头部头部选项集与服务端的无法匹配,服务端需要作出猜测。

客户端头部集 服务端响应头部
Accept:告知服务端客户端支持的媒体类型 Content-Type:服务端根据内容协商机制选择的媒体类型
Accept-Language:告知服务端客户端支持的语言 Content-Language:服务端根据内容协商机制选择的语言
Accept-Charset:告知服务端客户端支持的字符集 Content-Type:服务端根据内容协商机制选择的字符集
Accept-Encoding:告知服务端客户端支持的编码方式 Content-Encoding:服务端根据内容协商机制选择的编码方式

透明协商:某个中间设备(通常是缓存代理)代表客户端进行协商。这样免除了服务器的协商开销,比客户端驱动快,但HTTP并没有此方面的规范。

HTTPS

HTTPS是安全超文本协议,是使用TLS/SSL加密的HTTP协议,可以理解为HTTPS=HTTP+TLS/SSL,是在TCP与HTTP之间加了一层TLS/SSL。为什么需要HTTPS呢,签名的内容介绍其实可以看出HTTP有一些突出的缺陷:

HTTPS针对HTTP的缺陷增加了:内容加密、身份验证、数据完整性保护。
要了解HTTPS需要对加密、身份验证、TLS/SSL有基本的理解:
SSL:安全套接字层,1994年为Netscape研发,SSL协议位于TCP协议与各种应用层协议之间,为数据通信提供安全支持
TLS:传输层安全,前身是SSL(最初版本SSL1.0、SSL2.0、SSL3.0,由Netscape开发),1999年从3.1版本开始被IETF标准化并改名为TLS,发展至今有:TLS1.0、TLS1.1、TLS1.2三个版本。SSL3.0和TLS1.0由于安全漏洞,已经很少被使用,TLS1.3改动较大,未被广泛使用,目前广泛使用的是TLS1.1、TLS1.2。
加密算法:
加密算法分有以下几种类型:

数字签名:签名是指在信息的后面加上的一段内容(这段内容是将信息经过hash后的值,再对hash值进行加密。这段内容称为签名信息)。签名一般使用私钥对消息的hash值进行签名;验证签名使用公钥对签名进行解密得到消息的hash值

数字签名既对验证了身份,有保证了数据完整性。

数字证书:
考虑这种情形:客户端如何获得服务端的公钥?当服务器将公钥分发给客户端时,如果一开始就被第三方劫持,然后第三方自己再伪造一对秘钥,将伪造的公钥发给客户端,当服务器发送数据给客户端时,第三方将信息进行劫持,用劫持得到的公钥进行解密后,然后用伪造的私钥将数据(数据可能被篡改)加密发送客户端,而客户端收到后使用伪造的公钥解密,整个过程是透明的,客户端对于信息泄露、数据被篡改都毫无感知。为了防止这种情况,数字证书就出现了。
数字证书是有权威的证书认证机构(Certificate Authority,CA)颁发给服务端的,CA机构通过服务端提供的相关信息生成证书,证书中包含持有人信息(证书所有者的专有名称、证书颁发机构名称、证书有效起始日期、证书过期日期、证书数据格式的版本号、序列号等)、服务器公钥、数字签名等,最重要的是公钥在数字证书中。
数字证书是如何保证公钥来自请求的服务器的?——》数字证书中有持有人的相关信息,通过这点可以确定其不是第三方。
证书也是可以伪造的,如何保证证书是真的?——》即使第三方有CA公钥,能改解析数字签名并篡改,但是篡改之后,第三方需要证书进行加密,但是第三方没有CA私钥,无法加密,强行加密会导致客户端无法解密(客户端只人CA的公钥)
一个证书包含三部分:证书内容(持有人信息、服务器公钥等)、哈希算法、数字签名。证书内容被哈希算法hash计算得到hash值(此值也称证书摘要),然后CA机构使用自己的私钥对证书摘要进行加密得到数字签名。
客户端发起请求时,服务器将数据证书发给客户端,客户端通过CA提供的公钥对数字签名进行解密得到hash值(即证书摘要),同时将证书内容使用相同的哈希算法进行hash得到另一个hash值,对比两个hash值,如果相等说明证书正确,如果不相等说明证书不正确。

HTTPS是安全的超文本传输协议,需对内容进行可逆加密以便接收者能解密,采用的加密方式如果是对称加密,使得秘钥一样,很容易破解,而如果是非对称加密,公钥也容易被他人截获且效率不高,所以HTTPS采用了对称和非对称混合加密方式,那么是怎么保证非对称公钥的安全、有效性以及对称秘钥的安全性,所以需要依托权威机构(即CA)来确保公钥的安全和有效性,接着采用协商机制来确定采用什么对称秘钥,HTTPS的TLS/SSL的四次握手确定会话秘钥就是这么来的。下图是TLS/SSL四次握手流程图:
第一次握手:客户端发送握手请求,包含如下信息:

第二次握手:服务端收到客户端的握手请求,保存随机数1,并向客户端发送响应信息,包括如下信息:

第三次握手:客户端收到服务器的响应,会先对服务器的数字证书进行验证:验证证书是否过期(证书中有过期日期),接着验证证书的合法性(使用客户端或者系统中CA提供的公钥对证书中的数组签名解密,得到哈希值1;接着对证书内容使用哈希算法计算出哈希值2,比较两者是否相等,相等则代表证书合法,不相等代表证书不合法并结束通信)。
证书验证通过后,客户端保存服务端响应中的随机数2和证书中的公钥(即服务器的公钥),接着向服务端发送如下内容:

第四次握手:服务器收到第三次握手信息后,会对客户端握手结束通知值a进行验证(即第一次握手和第二次握手内容计算hash,再进行比较),验证通过,会使用私钥解析出随机数3并保存,然后计算出会话秘钥(使用随机1、随机2、随机3进行计算),接着向客户端发送如下信息:

自此HTTPS四层握手结束,接下来HTTPS就会使用协商好的加密算法和会话秘钥(=随机数1、随机数2、随机数3,是对称加密方式)进行加密与解密。非对称加密用在对随机数3、客户端握手结束通知值a、服务器握手结束通知b进行加密与解密;对称加密用在对真正内容传输的加密与解密,会话秘钥由四次握手产生的随机数1、随机数2、随机数3生成(这样可以保证秘钥的随机性,加到安全 性);每次确认的加密算法都是随机的、会话秘钥的生成也是随机生成,这样可以保证基本每次用的算法、秘钥不一样,加大了安全性。

HTTP瓶颈与解决方案

HTTP版本发展至今,出现了不少瓶颈和解决方案,
常见的瓶颈有:

上一篇 下一篇

猜你喜欢

热点阅读