REST 简介
REST (表征性状态传输,英文:Representational State Transfer) 以其简洁高效无状态的接口风格,为如今的 WebService 接口指引了新的方向
WebService 接口回顾
简单的说,WebService 就是通过 http、xmpp等协议,以规定格式 (WSDL) 进行信息传输的应用程序接口 (API) 系统。
REST 概念介绍
REST 是 web 系统的架构风格。它对系统组件的设计和应用上进行了一些规范,提出了一个高效的、更易维护的软件系统设计风格。
以它为主体思想设计的系统就叫 RESTful,相应的接口就叫做 RESTful API。它在接口思想将传统的 基于 HTTP 的 URI 抽象成网格资源的实体,对资源的请求操作增删改查,正好对应 HTTP 协议的 POST、DELETE、PUT、GET方法。
REST 架构特性
- 性能:交互组件以用户预期的性能与网络效率作为主导因素
- 高扩展性:以组件的形式,进行对外以及组件间的交互
- 简单接口:接口功能的简单化,一个接口不包含较多的业务流程或复杂逻辑
- 可维护性:组件的更改不会对其它组件产生影响,甚至在程序远行时都可以进行修改
- 可见性:REST 接口本质上是 web 接口,不是基于代码或系统层级内部的调用。因此,其通信的数据都是可见的
- 可移植性:包括组件的代码与数据都是可移植的
- 可靠性:包括组件、链接、数据的可靠性,任一组件的失效都不会对整个系统的运行造成阻碍
REST 架构规范
- Client–server 模式
客户端不关心服务器的数据是怎么来的,服务端也不关心客户端把这些数据拿去是怎么用的。完全分离、独立开发,只需要接口不变。
- 无状态
客户端的每一个请求都是独立的,和上下文没有联系。服务器不保持客户端的状态(如 session),客户端的状态在请求中进行携带。
-
cache 机制
-
此处指的是客户端的缓存机制,不管是终端还是中间层的客户端,都要做好接口的数据缓存,要以后台数据缓存的标准去对 RESTful API 接口数据进行管理。 这样可以取消一些不必要的与服务端之间的交互,进一步提高扩展性和性能。
-
层次化的系统。中间代理、接入端、负载均衡、安全认证、业务层、逻辑层、数据层等等都要详情分开,每层的逻辑与对外接口具有独立性,与上层的业务无耦合。
-
客服端代码要求,服务端可以定制和扩展客户端可使用的代码。
-
统一接口,对整个系统提供的接口数据格式进行统一
RESTful URI
RESTful URI 是将接口的 URL 抽象成一个个网络资源裸体,好比是在本地文件路径一样,一层层的去找到那个文件,文件的路径就是这个资源的 URI。
良好的 RESTful URI 有以下几个原则
- 路径各级使用名词,而不是动词
- 可读性好,使用正规的英文单词,让别人一看就能知道这个接口是操作什么的
- 使用 - 来连接单词
- 全部使用小写
- 区分一个还是多个(可用复数)
- 除非是同一资源的条件查询,不用在 URL 后面加参数
- 最好是支持回退的,比如
/my/cat/white
可以访问,/my/cat
也可以访问 - URI 可以以用户的角度,进行上下文关联。比如对用户
1001
,他自己的信息就是/user/my/info
, 对管理员,看他的信息就是/user/1001/info
特此给出 github API 大家感受一下
{
current_user_url: "https://api.github.com/user",
current_user_authorizations_html_url: "https://github.com/settings/connections/applications{/client_id}",
authorizations_url: "https://api.github.com/authorizations",
code_search_url: "https://api.github.com/search/code?q={query}{&page,per_page,sort,order}",
emails_url: "https://api.github.com/user/emails",
emojis_url: "https://api.github.com/emojis",
events_url: "https://api.github.com/events",
feeds_url: "https://api.github.com/feeds",
followers_url: "https://api.github.com/user/followers",
following_url: "https://api.github.com/user/following{/target}",
gists_url: "https://api.github.com/gists{/gist_id}",
hub_url: "https://api.github.com/hub",
issue_search_url: "https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}",
issues_url: "https://api.github.com/issues",
keys_url: "https://api.github.com/user/keys",
notifications_url: "https://api.github.com/notifications",
organization_repositories_url: "https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}",
organization_url: "https://api.github.com/orgs/{org}",
public_gists_url: "https://api.github.com/gists/public",
rate_limit_url: "https://api.github.com/rate_limit",
repository_url: "https://api.github.com/repos/{owner}/{repo}",
repository_search_url: "https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}",
current_user_repositories_url: "https://api.github.com/user/repos{?type,page,per_page,sort}",
starred_url: "https://api.github.com/user/starred{/owner}{/repo}",
starred_gists_url: "https://api.github.com/gists/starred",
team_url: "https://api.github.com/teams",
user_url: "https://api.github.com/users/{user}",
user_organizations_url: "https://api.github.com/user/orgs",
user_repositories_url: "https://api.github.com/users/{user}/repos{?type,page,per_page,sort}",
user_search_url: "https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"
}
RESTful HTTP method
无状态下的安全机制
在 webservice 的应用中,一般都将其部署在独立的服务器上。 其作为一个专门的远程接口提供者,会被各类客户端调用,调用者的身份验证就是不可避免的了。
在目前已经施行 REST 接口的 webservice 提供商里,对安全认证的做法各有千秋,不少采用 OAuth 验证,每次请求都携带相应的 token ,这类方法比较通用和成熟些。
作为全球一线的云服务提供商的亚马逊网络服务系统(英语:Amazon Web Services,简称为AWS),采用了一套签名加密的认证方式,将 REST 的无状态性表现的更彻底。
* HTTP访问控制(CORS)与同源策略
跨站 HTTP 请求(Cross-site HTTP request)是指发起请求的资源所在域不同于该请求所指向资源所在的域的 HTTP 请求。
比如说,域名 A(http://aaa.example) 的某 Web 应用程序中通过<img>
标签引入了域名 B(http://bbb.foo) 站点的某图片资源(http://domainb.foo/image.jpg),域名A的那 Web 应用就会导致浏览器发起一个跨站 HTTP 请求。
出于安全考虑,浏览器会限制脚本中发起的跨站请求。比如,使用 XMLHttpRequest 对象发起 HTTP 请求就必须遵守同源策略(same-origin policy)。同源策略是浏览器的一项重要安全控制,可以防止页面内的脚本对非同源数据进行篡改。
注意:
跨域并非浏览器限制了发起跨站请求,而是跨站请求可以正常发起,但是返回结果被浏览器拦截了。最好的例子是crsf跨站攻击原理,请求是发送到了后端服务器无论是否跨域!注意:有些浏览器不允许从HTTPS的域跨域访问HTTP,比如Chrome和Firefox,这些浏览器在请求还未发出的时候就会拦截请求,这是一个特例。
XMLHttpRequest 同源策略可分为两种情况,此处先要简介一下什么是简单请求。
所谓的简单,是指:
- 只使用 GET, HEAD 或者 POST 请求方法。如果使用 POST 向服务器端传送数据,则数据类型(Content-Type)只能是 application/x-www-form-urlencoded, multipart/form-data 或 text/plain中的一种。
- 不会使用自定义请求头(类似于 X-Modified 这种)。
注意
此为 Gecko 2.0 标准,在这之前,POST 数据类型只有 text/plain 才算是简单请求,目前尽量还是以此为标准
简单请求下的 XHR 跨域
简单请发起的同源限制,只需要服务器端在 response Header 中加入 Access-Control-Allow-Origin: *
即可。
如果想仅允许来自 http://www.aaa.com
的跨域请求,可以设定成 Access-Control-Allow-Origin: http://www.aaa.com
非简单请求下的 XHR 跨域
非简单请求的跨域浏览器会有一个预请求的动作,先发出一个 OPTIONS 的请求。对所跨域的站点进行访问权限的试探。
OPTIONS /resources/post-here/ HTTP/1.1
Host: bbb.com
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin: http://aaa.com
此时,需要在服务器端进行更详情的跨域许可控制,在response 中加入以下 Header.
来源站点许可 Access-Control-Allow-Origin: http://aaa.com
HTTP 请求方式许可 Access-Control-Allow-Methods: POST, GET, OPTIONS
允许携带自定义 Access-Control-Allow-Headers: X-PINGOTHER
许可有效时间 Access-Control-Allow-Headers: X-PINGOTHER
凭证信息的请求的 XHR 跨域
跨域请求是不携带任何 cookie 的,即使符合 cookie 的携带规则,比中 http://aaa.domain.com 访问 http://aaa.domain.com,cookie 写在 domain.com 下。
此时要是想正常携带 cookie,需要对发起的 XMLHttpRequest 中一个标志位设置为true
。
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;