# HTTP基础
# URI与URL
Web
服务器资源名被称为统一资源标识符(Uniform Resource Identifier, URI)。URI
就像因特网上的邮件地址一样,在世界范围内唯一标识并定位信息资源。
URI
有两种形式,URL
和URN
。
统一资源定位符(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
上任意资源的手段,但是不同的方案(例如HTTP
、FTP
和SMTP
等)的语法不尽相同。
大部分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
包含访问资源所需要的全部信息。
相对URL
是URL
的一种便捷缩略记法。相对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-ASCII 7比特范围内,受限 |
# 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
,第一个得到广泛应用的版本,增加了HEAD
、POST
方法,增加了HTTP Headers
和响应状态码HTTP/1.1
,当前普遍使用的版本。- 持久连接(
Keep-Alive
),通道复用 - 增加了
PUT
、DELETE
,OPTIONS
等方法 - 新增断点续传,身份认证,状态管理,缓存等特性
- 持久连接(
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>
2
3
4
响应报文的格式:
<version> <status> <reason-phrase>
<headers>
<entity-body>
2
3
4
各部分具体描述如下:
部分 | 描述 |
---|---|
方法method | 客户端系统服务器对资源执行的动作,例如:GET 、HEAD 或者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
2
3
响应报文示例:
HTTP/1.1 200 OK
Content-type: text/plain
Content-length: 19
Hi! I'm a message!
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 ),响应的主体包含了引用了已创建资源的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~399重定向状态码
状态码 | 原因短语 | 含义 |
---|---|---|
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~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
特指浏览器中非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
对于文件这种二进制的数据非常低效。
# 接口中的GET和POST
指通过浏览器的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
相比,具有可嵌套和数据类型更丰富的优势。
# 关于安全性
# Web的结构组件
- 代理,位于客户端和服务器之间的
HTTP
中间实体 - 缓存,
HTTP
的仓库,使常用页面的副本可以保存在离客户端更近的地方 - 网关,连接其他应用程序的特殊
Web
服务器 - 隧道,对
HTTP
通信报文进行盲转发的特殊代理 - Agent代理,发起自动
HTTP
请求的半智能Web
客户端