Web服务器资源名被称为统一资源标识符(Uniform Resource Identifier, URI)。URI就像因特网上的邮件地址一样,在世界范围内唯一标识并定位信息资源。
URI有两种形式,URL和URN。
统一资源定位符(URL)是URI的最常见方式,描述了一台特定服务器上某资源的特定位置,可以明确说明如何从一个精确、固定的位置获取资源。
大部分URL都遵守的标准格式包含以下三个部分:
HTTP协议http://www.baidu.com/network/http.html统一资源名(URN)是作为特定内容的唯一名称使用,与资源所在地无关。使用这个与位置无关的URN,就可以将资源四处搬移,也可以用同一个名字通过多种网路访问协议来访问资源。
例如因特网标准文档RFC 2141可以命名为:urn:ietf:rfc:2141
URN仍然处于试验阶段。永久统一资源定位符(persistent uniform resource locators, PURL)使用URL来实现URN功能的一个例子。其基本思想是在搜索资源过程中引入另一个中间层,通过一个中间资源定位符服务器对资源的实际URL进行登记和跟踪。
URL提供了一种定位Internet上任意资源的手段,但是不同的方案(例如HTTP、FTP和SMTP等)的语法不尽相同。
大部分URL方案的URL语法建立在以下九个部分的通用格式上:
| 组件 | 描述 | 默认值 |
|---|---|---|
方案scheme | 访问服务器时使用的协议,有第一个:将其与URL其余部分分隔开,大小写无关 | - |
用户user | 访问时需要的用户名,@将用户和密码组件和URL其余部分分隔开 | 匿名 |
密码password | 用户名后面需要包含密码,中间由冒号(:)分隔 | <E-mail>地址 |
主机host | 资源宿主服务器的主机名或IP地址 | - |
端口port | 资源宿主服务器正在监听的端口号,很多方案都有默认端口号(HTTP的默认端口号为80) | 每个方案特有 |
路径path | 服务器上资源的本地名,用/将其与前面的URL组件分隔开,路径组件语法与服务器和方案有关。可以用/将HTTP URL的路径组件划分成一些路径段(path segment),每个路径段都有自己的参数params组件 | - |
参数params | 某些方案(例如FTP)可以用这个组件来输入参数,参数为名/值对,可以包含多个参数字段,字段之间以及与路径其余部分之间用分号(;)分隔 | - |
查询query | 某些方案(例如HTTP)用以传递参数以激活应用程序(比如数据库、公告板、搜索引擎等)。查询组件,没有通用格式,通常大部分网关希望查询字符串以名值对的形式出现名值对之间用&分隔;用?将其与URL其余部分分隔开 | - |
片段frag | 一小片或者一部分资源的名字。引用对象时,不会将frag传给服务器,只在客户端内部使用,通过#将其与URL其余部分分隔开 | - |
URL有两种方式,绝对的和相对的。绝对URL包含访问资源所需要的全部信息。
相对URL是URL的一种便捷缩略记法。相对URL是不完整的,要获取访问资源所需要的全部信息必须相对于基础(base)URL进行解析。
基于历史原因,URL采用US-ASCII字符集。为了保证URL的完整性,设计了转义序列。通过转义序列,可以用US-ASCII字符集的有限子集对任意紫府进行编码。
URL转义序列的编码机制包含一个百分号(%),后面跟着两个表示字符ASCII码的十六进制数。例如空格的ASCII码为32(0x20),编码之后就是%20。
在URL中,还有以下几种字符也会被转义:
US-ASCII可打印字符集中| 字符 | 保留/受限原因 |
|---|---|
% | 编码字符转义标志 |
/ | 路径组件中分隔路径段的定界符 |
. | 路径组件中使用 |
# | 分段定界符 |
? | 查询字符串定界符 |
; | 参数定界符 |
: | 方案、用户/口令以及主机/端口组件定界符 |
$,+ | 保留 |
@&= | 某些方案上下文有特殊含义 |
| `{} | ^~[]'` |
<>" | 不安全,在URL范围之外用意义 |
0x00-0x1F, 0x7F | US-ASCII不可打印字符,受限 |
>0x7F | 不在US-ASCII7比特范围内,受限 |
URL方案| 方案 | 描述 |
|---|---|
http | 超文本传入协议方案,除了没有用户名和密码外,与通用URL格式相符,默认端口80。 基本格式:http://<host>:<port>/<path>?<query>#<frag> |
https | 与http一致。默认端口443 |
mailto | mailto URL指向的是Email地址,与其他方案有所不同,与标准URL也有所不同,其语法记录在RFC 822中 基本格式:mailto:<RFC-822-addr-spec> |
ftp | 文件传输协议,用来从FTP服务器上下载或者上传文件,并获取FTP服务器的目录结构内容列表。基本格式:ftp://<user>:<password>@<host>:<port>/<path>;<params> |
rtsp, rtspu | RTSP URL是可以通过实时流传输协议解析的音/视频媒体资源标识符。rtspu表示使用UDP获取资源。基本格式:rtsp://<user>:<password>@<host>:<port>/<path> |
file | 表示一台指定主机(本地磁盘、网络文件系统、或其他一些文件共享系统)上可以直接访问的文件。 基本格式:file://<host>/<path> |
news | RFC 1036定义,用来访问一些特定的文章或者新闻组。news URL包含的信息不足以对资源进行定位,需要解释程序。基本格式:news:<newsgroup>``news:<new-article-id> |
telnet | 用于访问交互式业务。表示的是可通过telnet协议访问的交互式应用程序(资源)。基本格式:telnet://<user>:<password>@<host>:<port>/ |
一个HTTP事务由一条(从客户端发往服务器的)请求命令和一个(从服务器发回客户端的)响应结果组成。这种通信是通过名为HTTP报文(HTTP message)的格式化数据块进行的。
HTTP/0.9,1991发布的原型版本,只支持GET方法。响应后就马上关闭连接HTTP/1.0,第一个得到广泛应用的版本,增加了HEAD、POST方法,增加了HTTP Headers和响应状态码HTTP/1.1,当前普遍使用的版本。
Keep-Alive),通道复用PUT、DELETE,OPTIONS等方法HTTP/2.0,数据以二进制分帧进行传输,头信息压缩,支持服务端推送HTTPS,使用SSL加密传输的HTTP安全版本HTTP报文是在HTTP应用程序之间发送的数据块,以文本形式的原信息(meta-information)开头,描述了报文的内容和含义,后面跟着可选的数据部分。
HTTP使用术语流入(inbound)和流出(outbound)来描述事物处理(transaction)的方向。报文流入源端服务器,工作完成后回流用户的Agent代理中。
HTTP报文会像水一样流动,向下游(downstream)流动。所有报文的发送者都在接受者的上游(upstream)。
HTTP报文是简单的格式化数据块,由以下三部分组成:
起始行和首部由行分隔,每行以一个由回车符(ASII码 13)和换行符(ASII码 10)组成的行终止序列(CRLF)作为结束。但稳健的应用程序通常也接受单个换行符作为行的终止,因为有些老的或者不完整的HTTP应用程序并不总是即发送回车符,又发送换行符。
主体(body)是一个可选的数据块,可以包含文本或者二进制数据。
HTTP报文可以分为两类,请求报文(request message)和响应报文(response message)。请求报文向Web服务器请求一个动作。响应报文将请求的结果返回给客户端。
请求报文的格式:
响应报文的格式:
各部分具体描述如下:
| 部分 | 描述 |
|---|---|
方法method | 客户端系统服务器对资源执行的动作,例如:GET、HEAD或者POST |
请求地址request URL | 所请求资源的完整URL |
版本version | 报文所使用HTTP版本,格式如下:HTTP/<major>.<minor> |
状态码status code | 三位数字,描述请求过程发生的情况。第一位用于描述状态的一般类别 |
原因短语reason phrase | 状态码的可读版本,包含行终止符之前的所有文本 |
首部header | 可以有0个或者多个首部。是一些系列的名值对。具体参见HTTP首部 |
实体的主体部分entity body | 主要包含一个由任意数据组成的数据块。并不是所有的报文都包含实体部分 |
请求报文示例如下:
响应报文示例:
常用HTTP方法见下表:
| 方法 | 描述 | 是否包含主体 |
|---|---|---|
GET | 从服务器获取一份文档 | 否 |
HEAD | 只从服务器获取文档的首部 | 否 |
POST | 向服务器发送需要处理的数据 | 是 |
PUT | 将请求主体部分存储在服务器上 | 是 |
TRACE | 对可能经过代理服务器传送到服务器上的报文进行追踪 | 否 |
OPTIONS | 决定可以在服务器是上执行那些方法 | 否 |
DELETE | 从服务器上删除一份文档 | 否 |
状态码分类如下:
| 整体范围 | 已定义范围 | 分类 |
|---|---|---|
100~199 | 100~101 | 信息提示 |
200~299 | 200~206 | 成功 |
300~399 | 300~305 | 重定向 |
400~499 | 400~415 | 客户端错误 |
500~599 | 500~505 | 服务器错误 |
HTTP/1.1引入了信息性状态码,这些状态码相对较新,因其复杂性和感知价值尚存在一些争论,而受到限制。
| 状态码 | 原因短语 | 含义 |
|---|---|---|
100 | Continue | 说明收到了请求的初始部分,请客户端继续。发送了这个状态码之后,服务器在收到请求之后,必须进行响应。 |
101 | Switching Protocals | 说明服务器正在根据客户端的指定,将协议切换成Update首部所列的协议 |
100 Continue状态码是针对如下情况:客户端在发送一个有实体的主体部分之前,期望查看下服务器是否接受这个实体。
首先,客户端需要发送一个包含了Expect: 100-continue首部的请求。这是一种优化,客户端只有在避免向服务器发送一个无法处理或使用大实体时,才使用100 Continue。
服务器接受了该请求之后,用100 Continue状态码或者错误码响应。如果在发送100 Continue状态码之前,就收到了部分(或全部)实体,服务器就不需要发送这个状态码了,而是跳过这个阶段,在读完请求之后,发送一个最终的状态码。
代理接受到包含Expect: 100-continue首部的请求,若知道下一个服务器兼容HTTP/1.1,或者不知道是否兼容,都应该将Expect首部放在请求中向下转发。如果知道不兼容HTTP/1.1,则以417 Expectation Failed响应。
| 状态码 | 原因短语 | 含义 |
|---|---|---|
200 | OK | 请求成功,实体的主体部分包含了所请求的资源 |
201 | Created | 用于创建服务器对象的请求(如PUT),响应的主体包含了引用了已创建资源的URL,Location首部包含了具体引用 |
202 | Accepted | 请求已被接受,但服务器还未对其执行任何操作。不能保证服务器会完成这个请求,只表示接受请求时是有效的。应该在body中包含请求状态描述,以及预计完成时间(或者一个可以获取此信息的指针) |
203 | Non-Authoritative Infomation | 实体首部包含的信息不是来自源服务器,而是来自资源的一份副本。如果中间节点上有副本,但无法或者没有对它所发送的资源有关元信息(首部)进行验证,就会出现这种情况。不是非用不可的,如果实体首部来自源服务器,相应为200的应用程序可以将其作为一种可选项使用 |
204 | No Content | 相应报文中包含若干首部和状态行,没有body。主要用于在浏览器不转为显示新文档的情况下,对其进行更新(如刷新一个表单) |
205 | Reset Content | 用于告知浏览器清除当前前面中的所有HTML表单元素 |
206 | Partial Content | 成功执行了一个部分或者Range请求。可以通过特殊的首部来获取部分或者某个范围内的文档。响应中必须包含Content-Range、Date以及Etag或Content Location首部 |
| 状态码 | 原因短语 | 含义 |
|---|---|---|
300 | Moltiple Choice | 请求一个实际指向多个资源的URL时返回的状态码,带有一个选项列表,Location首部包含首选URL |
301 | Moved Permanently | 请求的URL被移除,Location首部包含新URL |
302 | Found | 临时重定向,Location首部包含临时地址,将来还请求这个URL。HTTP 1.0加入,但是POST有问题,所以HTTP 1.1增加了303,很多浏览器将其当做303处理 |
303 | See Other | 用Location首部的地址来获取资源,主要目的是允许POST请求将客户端定位到某个资源上,会将POST转为GET |
304 | Not Modified | 结合不同首部不同意义。对于GET请求,表明资源未被修改,响应不包含body部分 |
305 | Use Proxy | 用Location首部返回的代理地址访问资源 |
307 | Temporary Redirect | 与303类似,但是需要跟用户询问是否应该在新URI上发起POST方法,不会转为GET |
| 状态码 | 原因短语 | 含义 |
|---|---|---|
400 | Bad Request | 客户端发送了一个错误的请求 |
401 | Unauthorized | 无访问权限,需要进行验证 |
402 | Payment Required | 保留状态码,供未来使用 |
403 | Forbidden | 请求被服务器拒绝,用于服务器不想说明拒绝原因 |
404 | Not Found | 服务器无法找到所请求的URL,通常会包含一个404页面供浏览器展示给用户看 |
405 | Mothod Not Allowed | 请求方法对于的URL不支持。在响应body中包含Allow首部,告知可以使用那些方法 |
406 | Not Acceptable | 客户端可以指定参数用以说明可接受的实体类型。表明服务器没有对应资源。一般服务器会包含一些首部,告知客户端原因 |
407 | Proxy Authentication Required | 与401类似,用于对资源进行验证的代理服务器 |
408 | Request Timeout | 完成客户端的请求耗时过长时,发送此状态码,并关闭连接 |
HTTP首部字段向请求报文和响应报文中添加了一些附加消息。HTTP首部是一系列的名/值对列表。可分为以下几类:
将长的首部行分为多行可以提高可读性,被称之为首部延续行,多出来的每行前面至少要有一个空格或者制表符(Tab)
特指浏览器中非Ajax的HTTP请求,浏览器GET用于读取一个资源,POST用于提交一个表单。GET请求是没有副作用的,是幂等的,而POST请求用副作用,是不幂等的,但是接口中POST是可以幂等的。
因为GET是读取,可以对GET请求的数据做缓存。可以做缓存浏览器本身上(彻底避免浏览器发请求),也可以做到代理上(如nginx),或者做到server端(用Etag,至少可以减少带宽消耗)。而POST不能缓存,也不能保存为书签。如果尝试重新执行POST请求,浏览器会弹一个框提示下刷新可能会有副作用,询问要不要继续。
GET和POST携带数据的格式也有区别,GET请求的数据附在URL上而POST请求的数据在body里。并不是GET只能用URL,而是浏览器直接发出的GET只能由一个URL触发。所以GET请求参数只能在URL上附带query string,但HTTP协议本身并没有这个限制。
浏览器的POST请求都来自表单提交,表单的数据被浏览器用编码到HTTP请求的body里。主要有有两种格式,一种是application/x-www-form-urlencoded,用来传输类似key1=value1&key2=value2这样的简单数据;另外一种是multipart/form-data,用来传输文件。因为application/x-www-form-urlencoded对于文件这种二进制的数据非常低效。
指通过浏览器的Ajax,或者iOS/Android等的HTTP Client发出的GET和POST请求。此时GET/POST不光能用在前端和后端的交互中,还能用在后端各个子服务的调用中(即当一种RPC协议使用)。
从HTTP协议本身看,并没有什么限制GET一定不能没有body,POST一定不能把参书放到URL的查询参数(query string)上。为了统一风格,形成了一系列的接口规范/风格,例如REST、GraphQL等。REST推荐在body中使用application/json格式,与x-www-form-urlencoded相比,具有可嵌套和数据类型更丰富的优势。
HTTP中间实体HTTP的仓库,使常用页面的副本可以保存在离客户端更近的地方Web服务器HTTP通信报文进行盲转发的特殊代理HTTP请求的半智能Web客户端HTTP/2旨在解决HTTP/1.1的性能问题,没有改变HTTP的语义(方法、状态码等),改变了数据传输的格式和方式。
主要特点与改进:
HPACK算法对HTTP头部进行压缩,大幅减少了冗余头部数据的传输。HTTP/3是下一代协议,它通过彻底更换底层传输协议来解决HTTP/2遗留的TCP队头阻塞问题。
主要特点与革命:
QUIC协议: 这是最根本的改变。QUIC不再使用TCP,而是基于UDP协议,并在其上实现了可靠传输。QUIC在协议层面原生实现了多路复用。每个数据流都是独立的,单个数据流的丢包只会影响该流本身,其他流完全不受影响。这彻底解决了TCP队头阻塞问题,使得单个连接能并行处理多个请求。QUIC将加密和连接建立合二为一。对于访问过的服务器,它可以实现0-RTT的握手,意味着在第一次发送数据时就可以携带应用数据,极大降低延迟。TCP连接会中断。而QUIC使用连接ID来标识连接,网络切换时只要ID不变,连接就能无缝保持。