HTTP基础

URI与URL

Web服务器资源名被称为统一资源标识符(Uniform Resource Identifier, URI)。URI就像因特网上的邮件地址一样,在世界范围内唯一标识并定位信息资源。

URI有两种形式,URLURN

统一资源定位符(URL)是URI的最常见方式,描述了一台特定服务器上某资源的特定位置,可以明确说明如何从一个精确、固定的位置获取资源。

大部分URL都遵守的标准格式包含以下三个部分:

  • 方案(scheme),表示资源使用的协议类型。如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语法

URL提供了一种定位Internet上任意资源的手段,但是不同的方案(例如HTTPFTPSMTP等)的语法不尽相同。

大部分URL方案的URL语法建立在以下九个部分的通用格式上:

<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
组件描述默认值
方案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包含访问资源所需要的全部信息。

相对URLURL的一种便捷缩略记法。相对URL是不完整的,要获取访问资源所需要的全部信息必须相对于基础(base)URL进行解析。

URL字符集

基于历史原因,URL采用US-ASCII字符集。为了保证URL的完整性,设计了转义序列。通过转义序列,可以用US-ASCII字符集的有限子集对任意紫府进行编码。

URL转义序列的编码机制包含一个百分号(%),后面跟着两个表示字符ASCII码的十六进制数。例如空格的ASCII码为32(0x20),编码之后就是%20

URL中,还有以下几种字符也会被转义:

  • 由于有特殊含义被作为保留字符
  • 不在US-ASCII可打印字符集中
  • 有些字符会与某些因特网网关和协议产生混淆
字符保留/受限原因
%编码字符转义标志
/路径组件中分隔路径段的定界符
.路径组件中使用
#分段定界符
?查询字符串定界符
;参数定界符
:方案、用户/口令以及主机/端口组件定界符
$,+保留
@&=某些方案上下文有特殊含义
`{}^~[]'`
<>"不安全,在URL范围之外用意义
0x00-0x1F, 0x7FUS-ASCII不可打印字符,受限
>0x7F不在US-ASCII7比特范围内,受限

URL方案

方案描述
http超文本传入协议方案,除了没有用户名和密码外,与通用URL格式相符,默认端口80。 基本格式:http://<host>:<port>/<path>?<query>#<frag>
httpshttp一致。默认端口443
mailtomailto URL指向的是Email地址,与其他方案有所不同,与标准URL也有所不同,其语法记录在RFC 822 基本格式:mailto:<RFC-822-addr-spec>
ftp文件传输协议,用来从FTP服务器上下载或者上传文件,并获取FTP服务器的目录结构内容列表。基本格式:ftp://<user>:<password>@<host>:<port>/<path>;<params>
rtsp, rtspuRTSP URL是可以通过实时流传输协议解析的音/视频媒体资源标识符。rtspu表示使用UDP获取资源。基本格式:rtsp://<user>:<password>@<host>:<port>/<path>
file表示一台指定主机(本地磁盘、网络文件系统、或其他一些文件共享系统)上可以直接访问的文件。 基本格式:file://<host>/<path>
newsRFC 1036定义,用来访问一些特定的文章或者新闻组。news URL包含的信息不足以对资源进行定位,需要解释程序。基本格式:news:<newsgroup>``news:<new-article-id>
telnet用于访问交互式业务。表示的是可通过telnet协议访问的交互式应用程序(资源)。基本格式:telnet://<user>:<password>@<host>:<port>/

HTTP事务

一个HTTP事务由一条(从客户端发往服务器的)请求命令和一个(从服务器发回客户端的)响应结果组成。这种通信是通过名为HTTP报文(HTTP message)的格式化数据块进行的。

HTTP协议版本

  • HTTP/0.9,1991发布的原型版本,只支持GET方法。响应后就马上关闭连接
  • HTTP/1.0,第一个得到广泛应用的版本,增加了HEADPOST方法,增加了HTTP Headers和响应状态码
  • HTTP/1.1,当前普遍使用的版本。
    • 持久连接(Keep-Alive),通道复用
    • 增加了PUTDELETEOPTIONS等方法
    • 新增断点续传,身份认证,状态管理,缓存等特性
  • HTTP/2.0,数据以二进制分帧进行传输,头信息压缩,支持服务端推送
  • HTTPS,使用SSL加密传输的HTTP安全版本

HTTP报文

报文流

HTTP报文是在HTTP应用程序之间发送的数据块,以文本形式的原信息(meta-information)开头,描述了报文的内容和含义,后面跟着可选的数据部分。

HTTP使用术语流入(inbound)和流出(outbound)来描述事物处理(transaction)的方向。报文流入源端服务器,工作完成后回流用户的Agent代理中。

HTTP报文会像水一样流动,向下游(downstream)流动。所有报文的发送者都在接受者的上游(upstream)。

报文的组成部分

HTTP报文是简单的格式化数据块,由以下三部分组成:

  • 起始行(start line),对报文进行描述
  • 首部(header),包含属性
  • 主体(body),可选的,包含数据

起始行和首部由行分隔,每行以一个由回车符(ASII码 13)和换行符(ASII码 10)组成的行终止序列(CRLF)作为结束。但稳健的应用程序通常也接受单个换行符作为行的终止,因为有些老的或者不完整的HTTP应用程序并不总是即发送回车符,又发送换行符。

主体(body)是一个可选的数据块,可以包含文本或者二进制数据。

HTTP报文的语法

HTTP报文可以分为两类,请求报文(request message)和响应报文(response message)。请求报文向Web服务器请求一个动作。响应报文将请求的结果返回给客户端。

请求报文的格式:

<method> <request-URL> <version> <headers> <entity-body>

响应报文的格式:

<version> <status> <reason-phrase> <headers> <entity-body>

各部分具体描述如下:

部分描述
方法method客户端系统服务器对资源执行的动作,例如:GETHEAD或者POST
请求地址request URL所请求资源的完整URL
版本version报文所使用HTTP版本,格式如下:HTTP/<major>.<minor>
状态码status code三位数字,描述请求过程发生的情况。第一位用于描述状态的一般类别
原因短语reason phrase状态码的可读版本,包含行终止符之前的所有文本
首部header可以有0个或者多个首部。是一些系列的名值对。具体参见HTTP首部
实体的主体部分entity body主要包含一个由任意数据组成的数据块。并不是所有的报文都包含实体部分

请求报文示例如下:

GET /test/hi-there.txt HTTP/1.1 Accept: text/* Host: www.haozhenjia.com

响应报文示例:

HTTP/1.1 200 OK Content-type: text/plain Content-length: 19 Hi! I'm a message!

HTTP方法

常用HTTP方法见下表:

方法描述是否包含主体
GET从服务器获取一份文档
HEAD只从服务器获取文档的首部
POST向服务器发送需要处理的数据
PUT将请求主体部分存储在服务器上
TRACE对可能经过代理服务器传送到服务器上的报文进行追踪
OPTIONS决定可以在服务器是上执行那些方法
DELETE从服务器上删除一份文档

HTTP状态码

状态码分类如下:

整体范围已定义范围分类
100~199100~101信息提示
200~299200~206成功
300~399300~305重定向
400~499400~415客户端错误
500~599500~505服务器错误

100~199信息性状态码

HTTP/1.1引入了信息性状态码,这些状态码相对较新,因其复杂性和感知价值尚存在一些争论,而受到限制。

状态码原因短语含义
100Continue说明收到了请求的初始部分,请客户端继续。发送了这个状态码之后,服务器在收到请求之后,必须进行响应。
101Switching 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~299成功状态码

状态码原因短语含义
200OK请求成功,实体的主体部分包含了所请求的资源
201Created用于创建服务器对象的请求(如PUT),响应的主体包含了引用了已创建资源的URLLocation首部包含了具体引用
202Accepted请求已被接受,但服务器还未对其执行任何操作。不能保证服务器会完成这个请求,只表示接受请求时是有效的。应该在body中包含请求状态描述,以及预计完成时间(或者一个可以获取此信息的指针)
203Non-Authoritative Infomation实体首部包含的信息不是来自源服务器,而是来自资源的一份副本。如果中间节点上有副本,但无法或者没有对它所发送的资源有关元信息(首部)进行验证,就会出现这种情况。不是非用不可的,如果实体首部来自源服务器,相应为200的应用程序可以将其作为一种可选项使用
204No Content相应报文中包含若干首部和状态行,没有body。主要用于在浏览器不转为显示新文档的情况下,对其进行更新(如刷新一个表单)
205Reset Content用于告知浏览器清除当前前面中的所有HTML表单元素
206Partial Content成功执行了一个部分或者Range请求。可以通过特殊的首部来获取部分或者某个范围内的文档。响应中必须包含Content-RangeDate以及EtagContent Location首部

300~399重定向状态码

状态码原因短语含义
300Moltiple Choice请求一个实际指向多个资源的URL时返回的状态码,带有一个选项列表,Location首部包含首选URL
301Moved Permanently请求的URL被移除,Location首部包含新URL
302Found临时重定向,Location首部包含临时地址,将来还请求这个URLHTTP 1.0加入,但是POST有问题,所以HTTP 1.1增加了303,很多浏览器将其当做303处理
303See OtherLocation首部的地址来获取资源,主要目的是允许POST请求将客户端定位到某个资源上,会将POST转为GET
304Not Modified结合不同首部不同意义。对于GET请求,表明资源未被修改,响应不包含body部分
305Use ProxyLocation首部返回的代理地址访问资源
307Temporary Redirect303类似,但是需要跟用户询问是否应该在新URI上发起POST方法,不会转为GET

400~499客户端错误状态码

状态码原因短语含义
400Bad Request客户端发送了一个错误的请求
401Unauthorized无访问权限,需要进行验证
402Payment Required保留状态码,供未来使用
403Forbidden请求被服务器拒绝,用于服务器不想说明拒绝原因
404Not Found服务器无法找到所请求的URL,通常会包含一个404页面供浏览器展示给用户看
405Mothod Not Allowed请求方法对于的URL不支持。在响应body中包含Allow首部,告知可以使用那些方法
406Not Acceptable客户端可以指定参数用以说明可接受的实体类型。表明服务器没有对应资源。一般服务器会包含一些首部,告知客户端原因
407Proxy Authentication Required401类似,用于对资源进行验证的代理服务器
408Request Timeout完成客户端的请求耗时过长时,发送此状态码,并关闭连接

HTTP首部

HTTP首部字段向请求报文和响应报文中添加了一些附加消息。HTTP首部是一系列的名/值对列表。可分为以下几类:

  • 通用首部,既可以出现在请求报文里,也可以出现在响应报文里
  • 请求首部,提供更多关于请求的信息
  • 响应首部,提供更多关于响应的信息
  • 实体首部,描述实体的长度和内容、或者资源自身
  • 扩展首部,规范中没有定义的首部

将长的首部行分为多行可以提高可读性,被称之为首部延续行,多出来的每行前面至少要有一个空格或者制表符(Tab)

GET与POST的区别

浏览器的GET和POST

特指浏览器中非AjaxHTTP请求,浏览器GET用于读取一个资源,POST用于提交一个表单。GET请求是没有副作用的,是幂等的,而POST请求用副作用,是不幂等的,但是接口中POST是可以幂等的。

因为GET是读取,可以对GET请求的数据做缓存。可以做缓存浏览器本身上(彻底避免浏览器发请求),也可以做到代理上(如nginx),或者做到server端(用Etag,至少可以减少带宽消耗)。而POST不能缓存,也不能保存为书签。如果尝试重新执行POST请求,浏览器会弹一个框提示下刷新可能会有副作用,询问要不要继续。

GETPOST携带数据的格式也有区别,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对于文件这种二进制的数据非常低效。

接口中的GET和POST

指通过浏览器的Ajax,或者iOS/Android等的HTTP Client发出的GETPOST请求。此时GET/POST不光能用在前端和后端的交互中,还能用在后端各个子服务的调用中(即当一种RPC协议使用)。

HTTP协议本身看,并没有什么限制GET一定不能没有bodyPOST一定不能把参书放到URL的查询参数(query string)上。为了统一风格,形成了一系列的接口规范/风格,例如RESTGraphQL等。REST推荐在body中使用application/json格式,与x-www-form-urlencoded相比,具有可嵌套数据类型更丰富的优势。

关于安全性

Web的结构组件

  • 代理,位于客户端和服务器之间的HTTP中间实体
  • 缓存,HTTP的仓库,使常用页面的副本可以保存在离客户端更近的地方
  • 网关,连接其他应用程序的特殊Web服务器
  • 隧道,对HTTP通信报文进行盲转发的特殊代理
  • Agent代理,发起自动HTTP请求的半智能Web客户端

HTTP/2 与 HTTP/3

HTTP/2

HTTP/2旨在解决HTTP/1.1的性能问题,没有改变HTTP的语义(方法、状态码等),改变了数据传输的格式和方式。

主要特点与改进:

  • 二进制分帧: 不再使用纯文本,而是将传输的数据分割为更小的二进制帧。这使得解析更快、更高效,错误更少。
  • 多路复用: 这是最核心的特性。在一个TCP连接上,可以同时交错地发送多个请求和响应帧。请求A和请求B的帧可以混杂在一起传输,服务器也能将其正确组装。这彻底解决了 HTTP 层面的队头阻塞,使得单个连接就能实现高效并行。
  • 头部压缩: 使用HPACK算法对HTTP头部进行压缩,大幅减少了冗余头部数据的传输。
  • 服务器推送: 服务器可以预测客户端的需要,在客户端请求一个资源(如HTML)时,主动将其他关联资源(如CSS、JS)推送给客户端,减少请求往返

HTTP/3

HTTP/3是下一代协议,它通过彻底更换底层传输协议来解决HTTP/2遗留的TCP队头阻塞问题。

主要特点与革命:

  • 基于QUIC协议: 这是最根本的改变。QUIC不再使用TCP,而是基于UDP协议,并在其上实现了可靠传输。
  • 解决TCP队头阻塞: QUIC在协议层面原生实现了多路复用。每个数据流都是独立的,单个数据流的丢包只会影响该流本身,其他流完全不受影响。这彻底解决了TCP队头阻塞问题,使得单个连接能并行处理多个请求。
  • 极快的连接建立: QUIC将加密和连接建立合二为一。对于访问过的服务器,它可以实现0-RTT的握手,意味着在第一次发送数据时就可以携带应用数据,极大降低延迟。
  • 连接迁移: 当你的网络在 Wi-Fi 和 5G 之间切换导致IP地址变化时,TCP连接会中断。而QUIC使用连接ID来标识连接,网络切换时只要ID不变,连接就能无缝保持。
  • 内建加密: 加密(TLS 1.3)是QUIC协议不可分割的一部分,所有HTTP/3流量都是加密的。