# 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>
1
组件 描述 默认值
方案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可打印字符集中
  • 有些字符会与某些因特网网关和协议产生混淆
字符 保留/受限原因
% 编码字符转义标志
/ 路径组件中分隔路径段的定界符
. 路径组件中使用
# 分段定界符
? 查询字符串定界符
; 参数定界符
: 方案、用户/口令以及主机/端口组件定界符
$,+ 保留
@&= 某些方案上下文有特殊含义
{}|\^~[]' 由于各种Agent代理比如网关的不安全处理,使用受限
<>" 不安全,在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报文(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>
1
2
3
4

响应报文的格式:

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

<entity-body>
1
2
3
4

各部分具体描述如下:

部分 描述
方法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
1
2
3

响应报文示例:

HTTP/1.1 200 OK
Content-type: text/plain
Content-length: 19

Hi! I'm a message!
1
2
3
4
5

# HTTP方法

常用HTTP方法见下表:

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

# HTTP状态码

状态码分类如下:

整体范围 已定义范围 分类
100~199 100~101 信息提示
200~299 200~206 成功
300~399 300~305 重定向
400~499 400~415 客户端错误
500~599 500~505 服务器错误

# 100~199信息性状态码

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~299成功状态码

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

# 300~399重定向状态码

状态码 原因短语 含义
300 Moltiple Choice 请求一个实际指向多个资源的URL时返回的状态码,带有一个选项列表,Location首部包含首选URL
301 Moved Permanently 请求的URL被移除,Location首部包含新URL
302 Found 临时重定向,Location首部包含临时地址,将来还请求这个URLHTTP 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~499客户端错误状态码

状态码 原因短语 含义
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首部字段向请求报文和响应报文中添加了一些附加消息。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客户端