REST概述
RESTful 是目前最流行的 API 设计规范,用于 Web 数据接口的设计。
REST即Representational state transfer(表现层状态转化),首次出现在Roy Thomas Fielding(HTTP协议1.0、1.1主要设计者,第一任Apache基金会主席…)的博士论文中,感兴趣的朋友,可参见https://www.ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation.pdf 76页第五章“Representational State Transfer (REST)”,或者查看中译版(李锟、廖志刚等)。
REST-中译版.pdf
REST目标
引用下Roy Fielding的原话:
This dissertation explores a junction on the frontiers of two research disciplines in computer science: software and networking. Software research has long been concerned with the categorization of software designs and the development of design methodologies, but has rarely been able to objectively evaluate the impact of various design choices on system behavior. Networking research, in contrast, is focused on the details of generic communication behavior between systems and improving the performance of particular communication techniques, often ignoring the fact that changing the interaction style of an application can have more impact on performance than the communication protocols used for that interaction. My work is motivated by the desire to understand and evaluate the architectural design of network-based application software through principled use of architectural constraints, thereby obtaining the functional, performance, and social properties desired of an architecture.
翻译过来,大意:本文主要目标是研究软件与网络的交叉点。软件研究很少涉及评估不同设计选择对系统行为影响,而是将关注点放在软件设计分类及演变上;而相反,网络研究很少涉及改变应用程序的互动风格相较改变互动协议对整体表现的影响,而是更多关注系统之间通信行为的细节、如何改进特定通信机制的表现。因此这篇文章的目的—理解和评估以网络为基础的应用软件的架构设计,得到一个功能、性能、通信方面更优的架构。
REST约束
客户-服务器(Client-Server):服务器、客户端隔离区分对待。
无状态(Stateless):来自客户的每一个请求,必须包含服务器处理该请求所需的所有信息,即服务器端无请求状态存储。
可缓存(Cachable):服务器无论是显示还是隐示,但必须让客户知道请求是否可以被缓存。
统一接口(Uniform Interface):客户和服务器之间通信的方法必须是统一化的。统一接口涵盖4条子约束:
- 资源Identifier:每个资源定义一个唯一标识,即通过这个唯一标识有且仅能找到该资源;
- 消息的自描述:client传递的消息需要能够提供足够信息告知server其自身该如何被处理。例如该消息所使用的MIME类型是html、xml、json还是其它,是否可以被缓存等。
- 资源的自描述:server端返回给client的消息能够足够描述自身即相关操作信息。如对资源的增、删等操作进行描述。
- 超媒体作为应用状态的引擎(HATEOAS):客户端通过服务器提供的动作来进行状态转换。
分层系统(Layered System):服务器和客户之间的通信标准化,即:允许服务器和客户之间的中间层可以代替服务器对客户的请求进行回应,而且这些对客户来说不需要特别支持。
支持按需代码(Code-On-Demand):可选约束,服务器可以提供一些代码或者脚本并在客户的运行环境中执行。
REST风格优势
通常使用的分布式应用架构风格有三种:
- 分布式对象(Distributed Objects,简称DO):架构实例如RMI、EJB/DCOM、.NET Remoting等;
- 远程过程调用(Remote Procedure Call,简称RPC):架构实例如SOAP、XML-RPC、Flash AMF等;
- 表述性状态转移(Representational State Transfer,简称REST):架构实例如HTTP、WebDAV等;
DO和RPC这两种架构风格在传统企业应用中非常普遍,REST则是Web应用的架构风格。
REST相较于DO、RPC,优势体现在:
- REST支持抽象的目标是资源,DO支持抽象的目标是对象,RPC支持抽象的目标是过程。REST中的资源,不需要依赖开发平台或编程语言;由于不同的编程语言对象的定义有很大差别,DO风格的架构通常与某种编程语言绑定的,若跨语言交互,实现起来也会非常复杂;REST风格以名词为核心,而RPC风格则以动词为核心。
- DO、RPC中无统一接口的概念。不同的API,接口设计风格可以完全不同。
- REST使用超文本,响应的内容中只包含消息本身,交互力度更大,效率相较DO更高。
- REST支持数据流和管道,而DO、RPC不支持。
- REST client与server端松耦合,RPC与DO风格通常会带来客户端与服务器端的紧耦合。
REST剖析
URI
在REST定义中,其实省略了URI(Uniform Resource Identifier)这个对象,这里对URI、URL、URN几个常用词做一个名词解释:
- URI(Uniform Resource Identifier):即统一资源标识,是统一紧凑的字符串表示物力资源或抽象;
- URL(Uniform Resource Loader):即我们常听到的统一资源定位符,是URI的子集,是URI两种形式中的一种,如https://www.baidu.com是URL,其侧重点在于“位置”定位;
URN(Uniform Resource Name):即统一资源名词,是URI的子集,是URI另一种形式,如urn:names:xml:1.0,“位置”无关,通常说的Magnet URI scheme(磁力链接)及时URN的一种实现;
Representation
表现层,通常把网络资源最终如何展现描述,称为“Representation”,比如,发送请求,请求接口,期望发送的信息体是“json”格式,期望接收到的结果也是“json”格式,那么对于这个请求的“表述”,可以定义header:
Content-Type: Application/json
- Accept: Application/json
State Transfer
REST约束中约定了无状态特性,这个无状态针对的是server端,client端需要维护client用户状态变化。通过HTTP协议,设置不同的请求“方法”,告知server端,server端接收到处理“资源”请求,并给出响应。URI是资源标识,在请求前后不变,而变动的是“资源”的“表现层”内容,client最终识别到“资源”“表现层”变化,因此称为“Representational State Transfer”。如client 端发送
请求,服务器端根据“资源”(/servers),返回结果GET /servers
Content-Type: application/json
Accept: application/json
{json data}
Content-Type: text/html;charset=utf-8
Response code: 200
RESTful API定义
符合REST规范设计的接口,称为RESTful API。
URI定义
版本(Version)
描述的是资源或接口的迭代阶段,通常version可以有3中定义方式:
版本定义在response的header中,如:
Accept: Application/json; version=1.1;
版本定义在response数据中,如返回data为JSON格式:
{
version: 1.1,
resource: {...}
}
版本定义在URI中,如:
GET /v1.1/resources
从笔者工作经历来讲,通常用到第3种,其理由:
- 用于前后端分离,提供JSON数据,header和data中不太好处理或区分;
- 调用接口时,已明确使用版本;
- version版本并非跟单个资源相关,而是跟单个独立项目相关;
资源(Resource)
通常,我们理解的Resource是指操作对象的数字化抽象,以虚拟机为例,其属性构成部分包括:
- 基础描述信息:ID、name、description、metadata等;
- 硬件组成信息:disks、nics、cpu、内存等;
- 管理信息:boot image、managed hypervisor等;
- 状态信息:task status、status等;
当然,对于一个虚拟机这样的资源,也可以进行:
- 创建、删除、重新配置、查询等操作;
- 迁移、快照、开关机、重启、挂起、唤醒、休眠等操作;
在URI定义时,实际优先根据需求进行操作对象“建模”,如上面的server,定义清楚Resource的属性构成及操作方法构成,之后再配合操作Method,定义Resource的各种操作API。通常情况下,建议在URI定义时使用复数定义resource,如”/servers”(并非说一定不能使用单数)。
过滤(filter)
严格来说,filters不属于URI定义部分,通常用于查询时使用,一般用途为:
- 分页分段查询:如”/servers?limit=10&maker=123356”;
- 根据资源属性过滤查询:如”/servers?name=test”;
- 过滤返回data显示字段:如”/servers?display_item=id,name,nics,disks”;
- 排序查询:如”/servers?field=created_at&order=desc”
其定义格式为:
?key1=values1&key2=value2
filter在定义时,需要注意:
- 根据url长度限制(不得超过255个字节),因此不要在filter总加入过长的过滤项;
对filter进行encode,尤其是包含中文、{}、[]等特殊符号时;
URI定义规则枚举
罗列若干URI定义规则建议:
URI字符全小写:定义URI时,尽量不用大写字母,如”/servers”;
- URI使用”/“区分层级:定义URI时,通常约定从左到右范围递减,如”GET /servers/123456”表示取servers中id为123456项,因此尽量不要以”/“作为URI结尾;
- 使用”-“而非”“作为单词连接:在浏览器经常在 URI 下加下划线,以表示可点击的视觉提示,”“容易被忽略;
- 尽量不要在URI定义中体现”.json、.html等”这样的后缀;
- 定义URI时使用名词且尽量使用复数;
操作方法(Method)
HTTP操作方法
常用的HTTP方法为:GET、POST、PUT、DELETE用以完成CURD操作,
- GET:通常用于获取查询列表或单个资源信息,如 ```http GET /v1/servers HTTP/1.1 Accept: application/json Content-Type: application/json
Response:
data:
[{
“name”: “host1”,
“id”: “123456”
}]
status: 200
- **POST**:用于创建新资源或者触发动作,如
```http
POST /v1/servers HTTP/1.1
data:
{
"name": "host1",
"flavor": "xxxx",
"image": "xxxx",
"nics": [{"net-id": "xxx"}]
}
Accept: application/json
Content-Type: application/json
Response:
data:
[{
"name": "host1",
"id": "123456",
"flavor": "xxxx",
"image": "xxxx",
"nics": [{"net-id": "xxx"}]
}]
status: 201
- PUT:用于更新资源属性,如 ```http PUT /v1/servers/123456 HTTP/1.1 data: { “name”: “host2” } Accept: application/json Content-Type: application/json
Response:
data:
[{
“name”: “host2”,
“id”: “123456”,
“flavor”: “xxxx”,
“image”: “xxxx”,
“nics”: [{“net-id”: “xxx”}]
}]
status: 200
- **DELETE**:用于删除资源,如
```http
DELETE /v1/servers/123456 HTTP/1.1
Accept: application/json
Content-Type: application/json
Response:
status: 202
除开上面的CURD操作对应的方法,还有OPTION、HEAD等不常用方法,
OPTION:在跨域或使用代理时,通常会用到OPTION方法,OPTION请求在于判定请求资源的选项或需求,或者服务器的能力;
HEAD:用来获取请求实体的元信息而不需要传输实体主体(entity-body)。此方法经常被用来测试超文本链接的有效性,可访问性,和最近的改变,例如获取虚拟机镜像信息,实体是镜像文件,通常调用HEAD方法获取镜像属性信息,通过GET方法获取镜像文件自身;
关于http方法详细定义,参看rfc文档。
安全性与幂等性
名词解释>
安全性:指调用http请求方法,执行结束后不会导致资源状态变化,详见Hypertext Transfer Protocol — HTTP/1.1-9.1.1;
幂等性:多次调用http请求方法,执行结果对资源改变等价,详见Hypertext Transfer Protocol — HTTP/1.1-9.1.2;
根据上面的定义,http方法,不能全部都无法确保多次请求得到的结果完全一致,http各常见方法安全性、幂等性见下表:
方法 | 安全性 | 幂等性 |
---|---|---|
GET | ||
OPTION | ||
HEAD | ||
POST | ||
PUT | ||
DELETE |
表现层定义
Header
HEADER是对RESTful API请求的描述,分为Request HEADER(client发送到server端,消息描述)和Response HEADER(server端返回消息描述),常见 Header Field Definitions。
Request相关HEADER(表格信息源自:HTTP Header 详解)
Header | 解释 | 示例 |
---|---|---|
Accept | 指定客户端能够接收的内容类型 | Accept: text/plain, text/html |
Accept-Charset | 浏览器可以接受的字符编码集。 | Accept-Charset: iso-8859-5 |
Accept-Encoding | 指定浏览器可以支持的web服务器返回内容压缩编码类型。 | Accept-Encoding: compress, gzip |
Accept-Language | 浏览器可接受的语言 | Accept-Language: en,zh |
Accept-Ranges | 可以请求网页实体的一个或者多个子范围字段 | Accept-Ranges: bytes |
Authorization | HTTP授权的授权证书 | Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Cache-Control | 指定请求和响应遵循的缓存机制 | Cache-Control: no-cache |
Connection | 表示是否需要持久连接。(HTTP 1.1默认进行持久连接) | Connection: close |
Cookie | HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。 | Cookie: $Version=1; Skin=new; |
Content-Length | 请求的内容长度 | Content-Length: 348 |
Content-Type | 请求的与实体对应的MIME信息 | Content-Type: application/x-www-form-urlencoded |
Date | 请求发送的日期和时间 | Date: Tue, 15 Nov 2010 08:12:31 GMT |
Expect | 请求的特定的服务器行为 | Expect: 100-continue |
From | 发出请求的用户的Email | From: user@email.com |
Host | 指定请求的服务器的域名和端口号 | Host: www.zcmhi.com |
If-Match | 只有请求内容与实体相匹配才有效 | If-Match: “737060cd8c284d8af7ad3082f209582d” |
If-Modified-Since | 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码 | If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
If-None-Match | 如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变 | If-None-Match: “737060cd8c284d8af7ad3082f209582d” |
If-Range | 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag | If-Range: “737060cd8c284d8af7ad3082f209582d” |
If-Unmodified-Since | 只在实体在指定时间之后未被修改才请求成功 | If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
Max-Forwards | 限制信息通过代理和网关传送的时间 | Max-Forwards: 10 |
Pragma | 用来包含实现特定的指令 | Pragma: no-cache |
Proxy-Authorization | 连接到代理的授权证书 | Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Range | 只请求实体的一部分,指定范围 | Range: bytes=500-999 |
Referer | 先前网页的地址,当前请求网页紧随其后,即来路 | Referer: http://www.zcmhi.com/archives/71.html |
TE | 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息 | TE: trailers,deflate;q=0.5 |
Upgrade | 向服务器指定某种传输协议以便服务器进行转换(如果支持) | Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 |
User-Agent | User-Agent的内容包含发出请求的用户信息 | User-Agent: Mozilla/5.0 (Linux; X11) |
Via | 通知中间网关或代理服务器地址,通信协议 | Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) |
Warning | 关于消息实体的警告信息 | Warn: 199 Miscellaneous warning |
Response相关HEADER(表格信息源自:HTTP Header 详解)
Header | 解释 | 示例 |
---|---|---|
Accept-Ranges | 表明服务器是否支持指定范围请求及哪种类型的分段请求 | Accept-Ranges: bytes |
Age | 从原始服务器到代理缓存形成的估算时间(以秒计,非负) | Age: 12 |
Allow | 对某网络资源的有效的请求行为,不允许则返回405 | Allow: GET, HEAD |
Cache-Control | 告诉所有的缓存机制是否可以缓存及哪种类型 | Cache-Control: no-cache |
Content-Encoding | web服务器支持的返回内容压缩编码类型。 | Content-Encoding: gzip |
Content-Language | 响应体的语言 | Content-Language: en,zh |
Content-Length | 响应体的长度 | Content-Length: 348 |
Content-Location | 请求资源可替代的备用的另一地址 | Content-Location: /index.htm |
Content-MD5 | 返回资源的MD5校验值 | Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ== |
Content-Range | 在整个返回体中本部分的字节位置 | Content-Range: bytes 21010-47021/47022 |
Content-Type | 返回内容的MIME类型 | Content-Type: text/html; charset=utf-8 |
Date | 原始服务器消息发出的时间 | Date: Tue, 15 Nov 2010 08:12:31 GMT |
ETag | 请求变量的实体标签的当前值 | ETag: “737060cd8c284d8af7ad3082f209582d” |
Expires | 响应过期的日期和时间 | Expires: Thu, 01 Dec 2010 16:00:00 GMT |
Last-Modified | 请求资源的最后修改时间 | Last-Modified: Tue, 15 Nov 2010 12:45:26 GMT |
Location | 用来重定向接收方到非请求URL的位置来完成请求或标识新的资源 | Location: http://www.zcmhi.com/archives/94.html |
Pragma | 包括实现特定的指令,它可应用到响应链上的任何接收方 | Pragma: no-cache |
Proxy-Authenticate | 它指出认证方案和可应用到代理的该URL上的参数 | Proxy-Authenticate: Basic |
refresh | 应用于重定向或一个新的资源被创造,在5秒之后重定向(由网景提出,被大部分浏览器支持) | Refresh: 5; url= http://www.zcmhi.com/archives/94.html |
Retry-After | 如果实体暂时不可取,通知客户端在指定时间之后再次尝试 | Retry-After: 120 |
Server | web服务器软件名称 | Server: Apache/1.3.27 (Unix) (Red-Hat/Linux) |
Set-Cookie | 设置Http Cookie | Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1 |
Trailer | 指出头域在分块传输编码的尾部存在 | Trailer: Max-Forwards |
Transfer-Encoding | 文件传输编码 | Transfer-Encoding:chunked |
Vary | 告诉下游代理是使用缓存响应还是从原始服务器请求 | Vary: * |
Via | 告知代理客户端响应是通过哪里发送的 | Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) |
Warning | 警告实体可能存在的问题 | Warning: 199 Miscellaneous warning |
WWW-Authenticate | 表明客户端请求实体应该使用的授权方案 | WWW-Authenticate: Basic |
Response Code
对于Response Code,通常指代HTTP Response code(详见 Status Code Definitions),有时也代指在返回data中的code,以http code为例,枚举(表格信息源自:HTTP状态码对照表):
状态码 | 状态码英文名称 | 中文描述 |
---|---|---|
1**:信息,服务器收到请求,需要请求者继续执行操作 | ||
100 | Continue | 继续。客户端应继续其请求 |
101 | Switching Protocols | 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议 |
2**:成功,操作被成功接收并处理 | ||
200 | OK | 请求成功。一般用于GET与POST请求 |
201 | Created | 已创建。成功请求并创建了新的资源 |
202 | Accepted | 已接受。已经接受请求,但未处理完成 |
203 | Non-Authoritative Information | 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本 |
204 | No Content | 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档 |
205 | Reset Content | 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域 |
206 | Partial Content | 部分内容。服务器成功处理了部分GET请求 |
3**:重定向,需要进一步的操作以完成请求 | ||
300 | Multiple Choices | 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择 |
301 | Moved Permanently | 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替 |
302 | Found | 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI |
303 | See Other | 查看其它地址。与301类似。使用GET和POST请求查看 |
304 | Not Modified | 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源 |
305 | Use Proxy | 使用代理。所请求的资源必须通过代理访问 |
306 | Unused | 已经被废弃的HTTP状态码 |
307 | Temporary Redirect | 临时重定向。与302类似。使用GET请求重定向 |
4**:客户端错误,请求包含语法错误或无法完成请求 | ||
400 | Bad Request | 客户端请求的语法错误,服务器无法理解 |
401 | Unauthorized | 请求要求用户的身份认证 |
402 | Payment Required | 保留,将来使用 |
403 | Forbidden | 服务器理解请求客户端的请求,但是拒绝执行此请求 |
404 | Not Found | 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置”您所请求的资源无法找到”的个性页面 |
405 | Method Not Allowed | 客户端请求中的方法被禁止 |
406 | Not Acceptable | 服务器无法根据客户端请求的内容特性完成请求 |
407 | Proxy Authentication Required | 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权 |
408 | Request Time-out | 服务器等待客户端发送的请求时间过长,超时 |
409 | Conflict | 服务器完成客户端的PUT请求是可能返回此代码,服务器处理请求时发生了冲突 |
410 | Gone | 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置 |
411 | Length Required | 服务器无法处理客户端发送的不带Content-Length的请求信息 |
412 | Precondition Failed | 客户端请求信息的先决条件错误 |
413 | Request Entity Too Large | 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息 |
414 | Request-URI Too Large | 请求的URI过长(URI通常为网址),服务器无法处理 |
415 | Unsupported Media Type | 服务器无法处理请求附带的媒体格式 |
416 | Requested range not satisfiable | 客户端请求的范围无效 |
417 | Expectation Failed | 服务器无法满足Expect的请求头信息 |
5**:服务器错误,服务器在处理请求的过程中发生了错误 | ||
500 | Internal Server Error | 服务器内部错误,无法完成请求 |
501 | Not Implemented | 服务器不支持请求的功能,无法完成请求 |
502 | Bad Gateway | 充当网关或代理的服务器,从远端服务器接收到了一个无效的请求 |
503 | Service Unavailable | 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中 |
504 | Gateway Time-out | 充当网关或代理的服务器,未及时从远端服务器获取请求 |
505 | HTTP Version not supported | 服务器不支持请求的HTTP协议的版本,无法完成处理 |
HyperMedia API
名词解释[HyperMedia](https://en.wikipedia.org/wiki/Hypermedia):超媒体是一个非线性介质的信息包括图形、音频、视频、文本和超链接。源于REST约束属性“超媒体作为应用状态的引擎HATEOAS”,在定义RESTful API时,通常在返回中加入HyperMedia链接。
如,对于JSON返回数据:
Request为:
GET /v2.1/e5ab2182bb984f3bb4773d4a83672549/servers/detail HTTP/1.1
Host: 192.168.10.111
Accept: application/json
Content-Type: application/json
Response为:
HTTP/1.1 200 OK
Content-Type: application/json
{"servers": [{
"status": "ACTIVE",
"links": [{
"href": "http://192.168.10.111:8774/v2.1/e5ab2182bb984f3bb4773d4a83672549/servers/95f684d4-0802-484e-b852-7ded35a8eeb5",
"rel": "self"
}, {
"href": "http://192.168.10.111:8774/e5ab2182bb984f3bb4773d4a83672549/servers/95f684d4-0802-484e-b852-7ded35a8eeb5",
"rel": "bookmark"
}],
"image": {
"id": "be4e8e37-226f-4784-b19d-a439400edca0",
"links": [{
"href": "http://192.168.10.201:8774/e5ab2182bb984f3bb4773d4a83672549/images/be4e8e37-226f-4784-b19d-a439400edca0",
"rel": "bookmark"
}]
},
"flavor": {
"id": "ed218eec-1e00-4ea9-93e7-f6e4e7c0ba93",
"links": [{
"href": "http://192.168.10.201:8774/e5ab2182bb984f3bb4773d4a83672549/flavors/ed218eec-1e00-4ea9-93e7-f6e4e7c0ba93",
"rel": "bookmark"
}]
},
"id": "95f684d4-0802-484e-b852-7ded35a8eeb5",
......
}]}
关于登陆验证
备注:此处单讨论说明登陆验证,是因为登陆验证违背了REST 无状态约束,因此对于登陆验证做一个专门的说明,限于篇幅,后续文档中详细介绍登陆及登陆实现!
什么是登陆验证
登陆验证要求
登陆验证源于用户使用WEB应用,记录用户身份状态的需求,其特点是:
- 用户使用用户相关信息(如常见的用户名、密码)验证后,对应服务器、client端可记录用户信息;
- 用户登陆后,不需要在交互时进行不断对于身份的告知,除非用户登陆状态过期或用户自动退出登陆;
用户登陆状态一般情况下是有过期时间的,通常定义为一段时间没有进行交互操作(如1小时),则任务登陆状态过期,server、client端自动移除用户登陆状态;
常见登陆验证方式
通常在web应用中,可见2种登陆验证方式:
server端提供自维护登陆状态:即访问的server端记录并维护用户的登陆状态信息;
- 第三方提供维护登陆状态:即由第三方server端记录并维护用户登陆状态信息,如常见的qq、微信、微博账号登陆,当然这种方式存在着“跨域问题”[后续文档专门讨论分析跨域问题];
验证实现若干方案
图片源于:https://auth0.com/blog/cookies-vs-tokens-definitive-guide/cookies方式
如上图,cookies方式,
- 在登陆时,在server端创建session,记录用户登陆状态及相关信息;
- 返回client后,client将session id存放于cookies中(浏览器可自动记录并存储);
当登陆后发送的后续请求,client在request header中携带cookies中的session id信息,server端接收到后,验证session id是否合法,若合法则进行相关处理并给出响应;
token方式
token方式,
在登陆时,在server端创建session,记录用户登陆状态及相关信息;
- 返回client后,client需要通过脚本控制存放token信息;
- 当登陆后发送的后续请求,client在request header或body中携带cookies中的session id信息,server端接收到后,验证session id是否合法,若合法则进行相关处理并给出响应;