⑴ REST是什么如何实现RESTful
REST (REpresentation State Transfer) 描述了一个架构样式的网络系统,比如 web 应用程序。它首次出现在 2000 年 Roy Fielding 的博士论文中,他是 HTTP 规范的主要编写者之一。REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。Web 应用程序最重要的 REST 原则是,客户端和服务器之间的交互在请求之间是无状态的。从客户端到服务器的每个请求都必须包含理解请求所必需的信息。如果服务器在请求之间的任何时间点重启,客户端不会得到通知。此外,无状态请求可以由任何可用服务器回答,这十分适合云计算之类的环境。客户端可以缓存数据以改进性能。在服务器端,应用程序状态和功能可以分为各种资源。资源是一个有趣的概念实体,它向客户端公开。资源的例子有:应用程序对象、数据库记录、算法等等。每个资源都使用 URI (Universal Resource Identifier) 得到一个惟一的地址。所有资源都共享统一的界面,以便在客户端和服务器之间传输状态。使用的是标准的 HTTP 方法,比如 GET、PUT、POST 和 DELETE。Hypermedia 是应用程序状态的引擎,资源表示通过超链接互联。另一个重要的 REST 原则是分层系统,这表示组件无法了解它与之交互的中间层以外的组件。通过将系统知识限制在单个层,可以限制整个系统的复杂性,促进了底层的独立性。当REST 架构的约束条件作为一个整体应用时,将生成一个可以扩展到大量客户端的应用程序。它还降低了客户端和服务器之间的交互延迟。统一界面简化了整个系统架构,改进了子系统之间交互的可见性。REST 简化了客户端和服务器的实现。RESTful的实现:RESTful Web 服务与 RPC 样式的 Web 服务了解了什么是什么是REST,我们再看看RESTful的实现。最近,使用 RPC 样式架构构建的基于 SOAP 的 Web 服务成为实现 SOA 最常用的方法。RPC 样式的 Web 服务客户端将一个装满数据的信封(包括方法和参数信息)通过 HTTP 发送到服务器。服务器打开信封并使用传入参数执行指定的方法。方法的结果打包到一个信封并作为响应发回客户端。客户端收到响应并打开信封。每个对象都有自己独特的方法以及仅公开一个 URI 的 RPC 样式 Web 服务,URI 表示单个端点。它忽略 HTTP 的大部分特性且仅支持 POST 方法。由于轻量级以及通过 HTTP 直接传输数据的特性,Web 服务的 RESTful 方法已经成为最常见的替代方法。可以使用各种语言(比如 Java 程序、Perl、Ruby、Python、PHP 和 Javascript[包括 Ajax])实现客户端。RESTful Web 服务通常可以通过自动客户端或代表用户的应用程序访问。但是,这种服务的简便性让用户能够与之直接交互,使用它们的 Web 浏览器构建一个 GET URL 并读取返回的内容。在REST 样式的 Web 服务中,每个资源都有一个地址。资源本身都是方法调用的目标,方法列表对所有资源都是一样的。这些方法都是标准方法,包括 HTTP GET、POST、PUT、DELETE,还可能包括 HEADER 和 OPTIONS。在RPC 样式的架构中,关注点在于方法,而在 REST 样式的架构中,关注点在于资源 —— 将使用标准方法检索并操作信息片段(使用表示的形式)。资源表示形式在表示形式中使用超链接互联。Leonard Richardson 和 Sam Ruby 在他们的著作 RESTful Web Services 中引入了术语 REST-RPC 混合架构。REST-RPC 混合 Web 服务不使用信封包装方法、参数和数据,而是直接通过 HTTP 传输数据,这与 REST 样式的 Web 服务是类似的。但是它不使用标准的 HTTP 方法操作资源。它在 HTTP 请求的 URI 部分存储方法信息。好几个知名的 Web 服务,比如 Yahoo 的 Flickr API 和 del.icio.us API 都使用这种混合架构。RESTful的实现:RESTful Web 服务的 Java 框架有两个 Java 框架可以帮助构建 RESTful Web 服务。erome Louvel 和 Dave Pawson 开发的 Restlet(见 参考资料)是轻量级的。它实现针对各种 RESTful 系统的资源、表示、连接器和媒体类型之类的概念,包括 Web 服务。在 Restlet 框架中,客户端和服务器都是组件。组件通过连接器互相通信。该框架最重要的类是抽象类 Uniform 及其具体的子类 Restlet,该类的子类是专用类,比如 Application、Filter、Finder、Router 和 Route。这些子类能够一起处理验证、过滤、安全、数据转换以及将传入请求路由到相应资源等操作。Resource 类生成客户端的表示形式。JSR-311是 Sun Microsystems 的规范,可以为开发 RESTful Web 服务定义一组 Java API。Jersey是对 JSR-311 的参考实现。JSR-311 提供一组注释,相关类和接口都可以用来将 Java 对象作为 Web 资源展示。该规范假定 HTTP 是底层网络协议。它使用注释提供 URI 和相应资源类之间的清晰映射,以及 HTTP 方法与 Java 对象方法之间的映射。API 支持广泛的 HTTP 实体内容类型,包括 HTML、XML、JSON、GIF、JPG 等。它还将提供所需的插件功能,以允许使用标准方法通过应用程序添加其他类型。RESTful的实现:构建 RESTful Web 服务的多层架构RESTful Web 服务和动态 Web 应用程序在许多方面都是类似的。有时它们提供相同或非常类似的数据和函数,尽管客户端的种类不同。例如,在线电子商务分类网站为用户提供一个浏览器界面,用于搜索、查看和订购产品。如果还提供 Web 服务供公司、零售商甚至个人能够自动订购产品,它将非常有用。与大部分动态 Web 应用程序一样,Web 服务可以从多层架构的关注点分离中受益。业务逻辑和数据可以由自动客户端和 GUI 客户端共享。惟一的不同点在于客户端的本质和中间层的表示层。此外,从数据访问中分离业务逻辑可实现数据库独立性,并为各种类型的数据存储提供插件能力。图1 展示了自动化客户端,包括 Java 和各种语言编写的脚本,这些语言包括 Python、Perl、Ruby、PHP 或命令行工具,比如 curl。在浏览器中运行且作为 RESTful Web 服务消费者运行的 Ajax、Flash、JavaFX、GWT、博客和 wiki 都属于此列,因为它们都代表用户以自动化样式运行。自动化 Web 服务客户端在 Web 层向 Resource Request Handler 发送 HTTP 响应。客户端的无状态请求在头部包含方法信息,即 POST、GET、PUT 和 DELETE,这又将映射到 Resource Request Handler 中资源的相应操作。每个请求都包含所有必需的信息,包括 Resource Request Handler 用来处理请求的凭据。从Web 服务客户端收到请求之后,Resource Request Handler 从业务逻辑层请求服务。Resource Request Handler 确定所有概念性的实体,系统将这些实体作为资源公开,并为每个资源分配一个惟一的 URI。但是,概念性的实体在该层是不存在的。它们存在于业务逻辑层。可以使用 Jersey 或其他框架(比如 Restlet)实现 Resource Request Handler,它应该是轻量级的,将大量职责工作委托给业务层。Ajax 和 RESTful Web 服务本质上是互为补充的。它们都可以利用大量 Web 技术和标准,比如 HTML、JavaScript、浏览器对象、XML/JSON 和 HTTP。当然也不需要购买、安装或配置任何主要组件来支持 Ajax 前端和 RESTful Web 服务之间的交互。RESTful Web 服务为 Ajax 提供了非常简单的 API 来处理服务器上资源之间的交互。图1 中的 Web 浏览器客户端作为 GUI 的前端,使用表示层中的 Browser Request Handler 生成的 HTML 提供显示功能。Browser Requester Handler 可以使用 MVC 模型(JSF、Struts 或 Spring 都是 Java 的例子)。它从浏览器接受请求,从业务逻辑层请求服务,生成表示并对浏览器做出响应。表示供用户在浏览器中显示使用。表示不仅包含内容,还包含显示的属性,比如 HTML 和 CSS。 业务规则可以集中到业务逻辑层,该层充当表示层和数据访问层之间的数据交换的中间层。数据以域对象或值对象的形式提供给表示层。从业务逻辑层中解耦 Browser Request Handler 和 Resource Request Handler 有助于促进代码重用,并能实现灵活和可扩展的架构。此外,由于将来可以使用新的 REST 和 MVC 框架,实现它们变得更加容易,无需重写业务逻辑层。数据访问层提供与数据存储层的交互,可以使用 DAO 设计模式或者对象-关系映射解决方案(如 Hibernate、OJB 或 iBATIS)实现。作为替代方案,业务层和数据访问层中的组件可以实现为 EJB 组件,并取得 EJB 容器的支持,该容器可以为组件生命周期提供便利,管理持久性、事务和资源配置。但是,这需要一个遵从 Java EE 的应用服务器(比如 JBoss),并且可能无法处理 Tomcat。该层的作用在于针对不同的数据存储技术,从业务逻辑中分离数据访问代码。数据访问层还可以作为连接其他系统的集成点,可以成为其他 Web 服务的客户端。数据存储层包括数据库系统、LDAP 服务器、文件系统和企业信息系统(包括遗留系统、事务处理系统和企业资源规划系统)。使用该架构,您可以开始看到 RESTful Web 服务的力量,它可以灵活地成为任何企业数据存储的统一 API,从而向以用户为中心的 Web 应用程序公开垂直数据,并自动化批量报告脚本。什么是REST:结束语REST 描述了一个架构样式的互联系统(如 Web 应用程序)。REST 约束条件作为一个整体应用时,将生成一个简单、可扩展、有效、安全、可靠的架构。由于它简便、轻量级以及通过 HTTP 直接传输数据的特性,RESTful Web 服务成为基于 SOAP 服务的一个最有前途的替代方案。用于 web 服务和动态 Web 应用程序的多层架构可以实现可重用性、简单性、可扩展性和组件可响应性的清晰分离。Ajax 和 RESTful Web 服务本质上是互为补充的。
⑵ ArcGIS Server REST 服务各类API的主要功能
这个问得比较大,REST是一个Web应用程序框架。ArcGIS REST API提供了简单、开放的接口来访问和使用ArcGIS Server发布的服务。使用ArcGIS REST API通过URL,可以获取和操作每一个服务中的所有资源和操作。使用REST API就是通过URL来向GIS服务器获取资源的操作。
一般客户端从服务器端总是能得到一个资源的表现,在此一般分为两种类型的资源:
Resources(资源,直接反应了服务本身的信息)
Operations(操作,根据服务本身的资源进行某些处理后得到的结果)
Catalog是整个REST APIURL分层等级的根。根下面是这个Server所发布的服务,一共有8种类型的服务:Map Service、Geocode Service、GP Service、Geometry Service、Image Service、Network Service、GeoData Service和Globe Service。每一种Service下面都有不同的操作和资源,而执行这些操作和获取这些资源都是通过URL。
再具体的建议参考《ArcGIS Server REST API Help》。
⑶ spring mvc restful风格的api怎么过滤相同路径
Restful风格的API是一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
在Restful风格中,用户请求的url使用同一个url而用请求方式:get,post,delete,put...等方式对请求的处理方法进行区分,这样可以在前后台分离式的开发中使得前端开发人员不会对请求的资源地址产生混淆和大量的检查方法名的麻烦,形成一个统一的接口。
在Restful风格中,现有规定如下:
GET(SELECT):从服务器查询,可以在服务器通过请求的参数区分查询的方式。
POST(CREATE):在服务器新建一个资源,调用insert操作。
PUT(UPDATE):在服务器更新资源,调用update操作。
PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。(目前jdk7未实现,tomcat7也不行)。
DELETE(DELETE):从服务器删除资源,调用delete语句。
了解这个风格定义以后,我们举个例子:
如果当前url是 http://localhost:8080/User
那么用户只要请求这样同一个URL就可以实现不同的增删改查操作,例如
http://localhost:8080/User?_method=get&id=1001这样就可以通过get请求获取到数据库 user 表里面 id=1001 的用户信息
http://localhost:8080/User?_method=post&id=1001&name=zhangsan这样可以向数据库 user 表里面插入一条记录
http://localhost:8080/User?_method=put&id=1001&name=lisi这样可以将 user表里面 id=1001 的用户名改为lisi
http://localhost:8080/User?_method=delete&id=1001这样用于将数据库 user 表里面的id=1001 的信息删除
这样定义的规范我们就可以称之为restful风格的API接口,我们可以通过同一个url来实现各种操作。
⑷ 如何优雅的设计Restful API URL
一个好的RESTful API,应该具备以下特征:
这个API应该是对浏览器友好的,能够很好地融入Web,而不是与Web格格不入。
1.浏览器是最常见和最通用的REST客户端。好的RESTful API应该能够使用浏览器+HTML完成所有的测试(不需要使用编程语言)。这样的API还可以很方便地使用各种自动化的Web功能测试、性能测试工具来做测试。Web前端应用(基于浏览器的RIA应用、移动App等等)也可以很方便地将多个RESTful API的功能组合起来,建造Mashup类的应用。
这个API中所包含的资源和对于资源的操作,应该是直观和容易理解的,并且符合HTTP协议的要求。
REST开发又被称作“面向资源的开发”,这说明对于资源的抽象,是设计RESTful API的核心内容。RESTful API建模的过程与面向对象建模类似,是以名词为核心的。这些名词就是资源,任何可命名的抽象概念都可以定义为一个资源。而HTTP协议并不是一种传输协议,它实际提供了一个操作资源的统一接口。对于资源的任何操作,都应该映射到HTTP的几个有限的方法(常用的有GET/POST/PUT/DELETE四个方法,还有不常用的PATCH/HEAD/OPTIONS方法)上面。所以RESTful API建模的过程,可以看作是具有统一接口约束的面向对象建模过程。
按照HTTP协议的规定,GET方法是安全且幂等的,POST方法是既不安全也不幂等的(可以用来作为所有写操作的通配方法),PUT、DELETE方法都是不安全但幂等的。将对资源的操作合理映射到这四个方法上面,既不过度使用某个方法(例如过度使用GET方法或POST方法),也不添加过多的操作以至于HTTP的四个方法不够用。
2.如果发现资源上的操作过多,以至于HTTP的方法不够用,应该考虑设计出更多的资源。设计出更多资源(以及相应的URI)对于RESTful API来说并没有什么害处。
这个API应该是松耦合的。
RESTful API的设计包括了三个循序渐进、由低到高的层次:资源抽象、统一接口、超文本驱动。正是这三个层次确保了RESTful API的松耦合性。
3.当设计面向互联网的API时,松耦合变成了一种“必须有”的强需求。紧耦合的API非常脆弱,一旦公布出去,服务器端和客户端都无法持续进化。尤其是服务器端,公布出去的接口根本不敢改,改了之后,几乎所有客户端应用立即无法正常工作。REST这种架构风格就是紧耦合API的解毒剂,这个话题可以谈的很深,这里就不展开了。感兴趣的读者可以参考《REST实战》。
这个API中所使用的表述格式应该是常见的通用格式
在RESTful API中,对于资源的操作,是通过在服务器端-客户端之间传递资源的表述来间接完成的。资源的表述可以有很多种格式,并且在响应和请求中的资源表述格式也会有所不同。GET/POST响应中的资源表述格式,常见的有HTML、XML、JSON;POST/PUT请求中的资源表述格式,常见的有标准的HTML表单参数、XML、JSON。
4.这些常见表述格式,处理起来非常容易,有大量的框架和库提供支持。所以除非有很合理的要求,通常不需要使用自定义的私有格式。
使用HTTP响应状态代码来表达各种出错情况
HTTP响应状态代码,是HTTP协议这个统一接口中用来表达出错情况的标准机制。响应状态代码分成两部分:status code和reason phase。两部分都是可定制的,也可以使用标准的status code,只定制reason phase。
5.如果一个所谓的“RESTful API”对于任何请求都返回200 OK响应,在响应的消息体中返回出错情况信息,这种做法显然不符合“确保操作语义的可见性”这个REST架构风格的基本要求。
这个API应该对于HTTP缓存是友好的
6.充分利用好HTTP缓存是RESTful API可伸缩性的根本。HTTP协议是一个分层的架构,从两端的user agent到origin server之间,可以插入很多中间组件。而在整个HTTP通信链条的很多位置,都可以设置缓存。HTTP协议内建有很好的缓存机制,可以分成过期模型和验证模型两套缓存机制。如果API设计者完全没有考虑过如何利用HTTP缓存,那么这个API的可伸缩性会有很多问题。
⑸ 如何在REST API中使用查阅项的值作为过滤条件
由于REST可以降低开发的复杂度,提高系统的可伸缩性,增强系统的可扩展性,简化应用系统之间的集成,因而得到了广大开发人员的喜爱,同时得到了业界广泛的支持。
⑹ Spring中拦截/和拦截/*的区别
一、我们都知道在基于Spring的Application中,需要在web.xml中增加下面类似的配置信息:
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- Spring MVC Servlet -->
<servlet>
<servlet-name>servletName</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>servletName</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
此处需要特别强调的是 <url-pattern>/</url-pattern>使用的是/,而不是/*,如果使用/*,那么请求时可以通过DispatcherServlet转发到相应的Action或者Controller中的,但是返回的内容,如返回的jsp还会再次被拦截,这样导致404错误,即访问不到jsp。所以如果以后发现总是有404错误的时候,别忘了check一下 <url-pattern>/</url-pattern>的配置是否是/*.
二、其实Spring 的Servlet拦截器匹配规则(即 <url-pattern>...</url-pattern> )都可以自己定义,例:当映射为@RequestMapping("/user/add")时
1、拦截*.do、*.htm, 例如:/user/add.do
这是最传统的方式,最简单也最实用。不会导致静态文件(jpg,js,css)被拦截。
2、拦截/,例如:/user/add
可以实现现在很流行的REST风格。很多互联网类型的应用很喜欢这种风格的URL。
弊端:会导致静态文件(jpg,js,css)被拦截后不能正常显示。想实现REST风格,事情就是麻烦一些。后面有解决办法还算简单。
3、拦截/*,这是一个错误的方式,请求可以走到Action中,但转到jsp时再次被拦截,不能访问到jsp。
三、如何访问到静态的文件,如jpg,js,css?
如果你的DispatcherServlet拦截"*.do"这样的有后缀的URL,就不存在访问不到静态资源的问题。
如果你的DispatcherServlet拦截"/",为了实现REST风格,拦截了所有的请求,那么同时对*.js,*.jpg等静态文件的访问也就被拦截了。
我们要解决这个问题。
目的:可以正常访问静态文件,不可以找不到静态文件报404。
方案一:激活Tomcat的defaultServlet来处理静态文件
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
特点:1. 要配置多个,每种文件配置一个。
2. 要写在DispatcherServlet的前面, 让 defaultServlet先拦截请求,这样请求就不会进入Spring了。
3. 高性能。
备注:
Tomcat, Jetty, JBoss, and GlassFish 自带的默认Servlet的名字 -- "default"
Google App Engine 自带的 默认Servlet的名字 -- "_ah_default"
Resin 自带的 默认Servlet的名字 -- "resin-file"
WebLogic 自带的 默认Servlet的名字 -- "FileServlet"
WebSphere 自带的 默认Servlet的名字 -- "SimpleFileServlet"
方案二: 在spring3.0.4以后版本提供了mvc:resources , 使用方法:
<!-- 对静态资源文件的访问 -->
<mvc:resources mapping="/images/**" location="/images/" />
images/**映射到 ResourceHttpRequestHandler进行处理,location指定静态资源的位置.可以是web application根目录下、jar包里面,这样可以把静态资源压缩到jar包中。cache-period 可以使得静态资源进行web cache
如果出现下面的错误,可能是没有配置<mvc:annotation-driven />的原因。
报错WARNING: No mapping found for HTTP request with URI [/mvc/user/findUser/lisi/770] in DispatcherServlet with name 'springMVC'使用<mvc:resources/>元素,把mapping的URI注册到SimpleUrlHandlerMapping的urlMap中,
key为mapping的URI pattern值,而value为ResourceHttpRequestHandler,
这样就巧妙的把对静态资源的访问由HandlerMapping转到ResourceHttpRequestHandler处理并返回,所以就支持classpath目录,jar包内静态资源的访问.
另外需要注意的一点是,不要对SimpleUrlHandlerMapping设置defaultHandler.因为对static uri的defaultHandler就是ResourceHttpRequestHandler,
否则无法处理static resources request.
方案三 ,使用<mvc:default-servlet-handler/>
<mvc:default-servlet-handler/>
会把"/**" url,注册到SimpleUrlHandlerMapping的urlMap中,把对静态资源的访问由HandlerMapping转到 org.springframework.web.servlet.resource. 处理并返回.
使用就是各个Servlet容器自己的默认Servlet.
补充说明:多个HandlerMapping的执行顺序问题:
的order属性值是:0
< mvc:resources/ > 自动注册的 SimpleUrlHandlerMapping 的order属性值是: 2147483646
<mvc:default-servlet-handler/>自动注册 的SimpleUrlHandlerMapping 的order属性值是: 2147483647
spring会先执行order值比较小的。当访问一个a.jpg图片文件时,先通过 来找处理器,一定是找不到的,因为我们没有叫a.jpg的Action。然后再按order值升序找,由于最后一个 SimpleUrlHandlerMapping 是匹配 "/**"的,所以一定会匹配上,就可以响应图片。 访问一个图片,还要走层层匹配。不知性能如何?
最后再说明一下,方案二、方案三 在访问静态资源时,如果有匹配的(近似)总拦截器,就会走拦截器。如果你在拦截中实现权限检查,要注意过滤这些对静态文件的请求。
如何你的DispatcherServlet拦截 *.do这样的URL后缀,就不存上述问题了。还是有后缀方便。
⑺ 在REST API上实现防抵赖、防篡改验证的简便方法
开放basic auth并且map到一个现有的数据库用户表或者一个xml文件就可以了。
防篡改可以加一个ACL 控制
⑻ 如何更好地设计REST API
由于REST可以降低开发的复杂度,提高系统的可伸缩性,增强系统的可扩展性,简化应用系统之间的集成,因而得到了广大开发人员的喜爱,同时得到了业界广泛的支持。比如IBM,Google等公司的很多产品都提供了REST API给开发人员;与此同时,大量的开源项目和云计算服务都提供了REST API接口。
而在最近,一些新产品的开发甚至已经几乎完全抛弃了传统的类似JSP的技术, 转而大量使用REST风格的构架设计, 即在服务器端所有商业逻辑都以REST API的方式暴露给客户端, 所有浏览器用户界面使用widget、Ajax、HTML5 等技术,用HTTP的方式与后台直接交互。
那么, 在REST API爆炸式增长的今天, 我们应该如何更好的设计我们的接口, 来提高我们的API的可用性,易用性,可维护性与可扩展性呢?本文将从以下方面与您探讨REST API设计方面的最佳实践:
如何规划资源标识结构与URI模式
如何根据应用场景提供内容协商
如何正确的使用HTTP响应代码
如何处理缓存和并发请求
如何利用数据冗余和链接元素
先决条件
如果您具有如下知识与经验,将有助于您阅读和理解本文章的内容 。
REST相关的基本知识;
HTTP协议的基本知识;
一定的Web开发经验。
REST简介
REST是英文Representational State Transfer的缩写,是近年来迅速兴起的,一种基于HTTP、URI以及XML这些现有协议与标准的,针对网络应用的设计和开发方式。它可以降低开发的复杂度,提高系统的可伸缩性。
REST的核心是可编辑的资源及其集合,用符合Atom文档标准的Feed和Entry表示。每个资源或者集合有一个惟一的URI。系统以资源为中心,构建并提供一系列的Web服务。REST的基本概念和原则包括:系统上的所有事物都被抽象为资源;每个资源对应唯一的资源标识;对资源的操作不会改变资源标识本身;所有的操作都是无状态的;等等。
在REST中,开发人员显式地使用HTTP方法,对系统资源进行创建、读取、更新和删除的操作:
使用POST方法在服务器上创建资源
使用GET方法从服务器检索某个资源或者资源集合
使用PUT方法对服务器的现有资源进行更新
使用DELETE方法删除服务器的某个资源
图 1. 用 HTTP 方法操作相册系统资源的简单范例
更好的规划你的资源标识结构与URI模式
REST 中,最基本的莫过于资源标识结构和URI模式了。更好的规划他们,是我们的API设计取得成功的最关键的一步。
首先,我们来看看基本资源类型
上文中提到,在REST构架的设计中,系统中的所有事物都被抽象为资源。
在一个文档系统中,文档、目录、注释、草稿等等,是组成系统的资源。
在一个银行系统中,客户信息、理财产品、利率信息、网点信息等等,是组成系统的资源。
在一个航空客票系统中,旅客信息、机票订单、航班信息、机场信息等等,是组成系统的资源。
这些资源,通常在系统中以“Entry”的形式出现。下面的代码样例向您展示了一个常见的“Entry”资源。
清单 1. 一个简单的Entry资源样例
以下是引用片段:
REST API 请求:
GET http://example.com/航班信息/CA827/entry
<entry>
<id> CA827 </id>
<link href="航班信息 /CA827/entry" rel="self"/>
<title type="text">CA827 </title>
<published>2010-08-24T02:35:40.937Z </published>
<updated>2010-08-24T02:35:40.937Z </updated>
<ca:from>Beijing </ca:from>
<ca:to>Changsha </ca:to>
<ca:time>09:30:00 </ca:time>
<ca:aircraft>AB330 </ca:aircraft>
<summary type="text"/>
</entry>
我们会注意到,这些资源,在描述了某种事物的同时,还有可能存在一定的层次结构关系。比如,文档从属于某个目录,注释从属于文档;旅客信息可以从属于机票订单,也可以从属于某个航班。
当我们的资源有这种层次关系的时候,我们不妨在URI模式的设计中,用复合的URI来帮助开发者更好的理解和设计资源。
比如, 针对一个文档的评论, 他的URI模式可以设计成如下:/文件夹/[文件夹名]/文件/[文件名]/评论/[ 评论唯一标示 ]。 这样,在构造和解析URI的过程中, 可以帮助开发者更好的理解系统,设计程序。
其次,我们来看看集合资源类型
资源,除了作为独立个体可以被访问,还可以由多个个体组合成一个集合,在系统中,通常以“feed”的形式存在。资源的集合, 可以是处于相同层次上,有相同从属关系的一组资源,比如一个文件夹下的所有文件; 也可以是根据某种条件查询出来的查询结果的资源集合,比如所有30岁以上40岁以下,拥有100万资产以上客户的名单。
下面,我们来讨论一下设计集合类型资源的REST API时需要考虑的问题。
使用过滤条件来帮助用户更准确地获取数据
我们要返回的资源集合,无论是否有相同从属关系,大部分时候都需要进行必要的过滤,提供足够的过滤参数,查询参数, 能够帮助开发者高效的,准确地获取所需要的数据。 在服务器端过滤数据通常比客户端高效,并且减少了不必要的数据传输,可以大大减少网络开销,提高执行效率。
最常见的过滤条件,是通过URL参数实现,比如/环境工程系/学生? 籍贯=北京&性别=女。
很多时候,我们需要制定更加复杂的过滤条件,那么我们可以有两种选择:
首先,我们可以使用正则表达式或者服务器可以理解的语法,比如/环境工程系/学生?filter=age between (15, 18)
其次,我们还可以使用POST方法,携带一个文件来描述复杂的查询条件,文件的格式与语法通常需要在服务器端有相应的设计与定义。不过通常POST方法没有缓存机制,因此不是查询数据的首选。
使用排序来帮助客户端更好的展现数据
虽然进行客户端排序对于开发者来说是件轻而易举的事情,但是直接得到已经排序的返回结果,仍然是大部分开发者所期望的。尤其是很多时候,我们在浏览器,使用 Widget 展示结果,不适宜在客户端存储大量数据进行内存排序。
排序, 通常有2个参数,一个是用来排序的字段,一个是排序的升序降续方式。比如我们可以用支持这样的参数组合的手段,提供基本的排序能力:?sortOrder=asc&sortField=age
使用分页来帮助客户端处理大量数据
由于返回的结果可能有几百几千条记录,将这些记录一次性的返回给客户端是不现实的,巨大的网络流量开销和客户端数据区的内存开销,都是我们在应用开发的时候不希望看到的,因此,如果你的集合资源有可能有大量的数据返回,请务必提供分页的功能支持。
我们通常用一个以上参数来制定一个返回结果的区域,比较常见的有下面两种:
一种常见于用固定行数的表格来展示数据,用当前处于第几页和每页返回多少行数据来确定需要的数据, 比如/所有学生?page=5&pagesize=50
另外一种常见于用更加灵活的界面展示数据,用从第几行开始,一共返回多少行数据来确定需要的数据, 比如/所有学生?startIndex=27&count=22
下面是一个来自IBM developerWorks的API样例,尝试请求该API,你可以看到该集合很好的支持了结果的分页与排序。同时我们从返回的信息中可以看到,每个文档Entry的URI都按照/社区库/[社区库ID]/文档/[文档ID]的复合URI的模式设计的。
清单 2. IBM developerWorks的某个社区文件库的集合资源的API
以下是引用片段:
REST API 请求:
GET https://www.ibm.com/developerworks/mydeveloperworks
/files/form/anonymous/api/communitylibrary
/0a7c97bb-6cf9-4ddb-a918-80994e7b444d/feed?
pageSize=5&page=1&sK=modified&sO=dsc
最后,我们来讨论一些特殊资源类型
理想的REST世界,一切事物都抽象为资源,一切操作都抽象为增删改查。然而,所有事物与操作都可以很容易的按照这个规则作抽象吗?让我们看看这个例子:
检入和检出一个文档----这个时候,我们要处理的资源是一个文档,然而增删改查似乎都无法与“检入检出”这个动作进行对应。当然,我们可以在文档资源中,设计一个检入检出状态的元素,通过编辑文档资源来实现。但是,这种设计从自然语义上看,并不是很贴切;并且增加了资源编辑操作的复杂度。
如果我们来定义一个新的集合----“我检出的文档”,用创建一个集合资源来对应检出(创建一个文档锁),用删除一个集合资源来对应检入(删除一个文档锁), 是不是逻辑上可以变得更加清楚?
在REST这个以名词为核心的构架结构中,当你遇到一些动词特性比较强的操作,而又很难用原始资源的增删改查来匹配的时候,不妨换个思路, 通过引入新的逻辑资源集合的方式, 来进行API的设计与规划。
理解和使用内容协商
我们的开发者在发送一个REST API请求的同时,根据应用场景,针对相同的资源,可能会期待不同的返回形式。
比如,我希望根据用户客户端语言,同一个资源的内容可以返回不同的语言。又比如,当我使用Java编程的时候,我希望得到ATOM格式的返回结果,而当我使用JavaScript编程的时候,我希望得到Json格式的返回结果。
因此,我们在设计REST API的时候,应该提供完备的内容协商能力。
使用URL参数进行内容协商
最容易想到的自然是通过URL参数进行控制,我们经常看到形如/航班号/entry? format=JSON这样的URL。这种方式的优势就是简单灵活, 你可以通过任何 URL 参数来组合你的输出格式。
下面是一个来自IBM developerWorks的API样例,尝试请求该API,你可以看到该集合是如何支持不同的输出格式请求的。
清单 3. IBM developerWorks的文件服务标签云的API
以下是引用片段:
REST API请求,要求返回XML格式数据:
GET https://www.ibm.com/developerworks/mydeveloperworks
/files/form/anonymous/api/tags/feed?format=xml
&scope=document&pageSize=30&sK=cloud&sO=dsc
REST API请求,要求返回JSON格式数据:
GET https://www.ibm.com/developerworks/mydeveloperworks
/files/form/anonymous/api/tags/feed?format=json
&scope=document&pageSize=30&sK=cloud&sO=dsc
使用Accept头进行内容协商
使用URL参数,简单灵活,但是也由此带来了设计上的随意和不标准。并且,过多的参数会导致URL的可读性变差,更有甚者,可能会导致URL过长,超出规范,API请求无法执行。
更为标准的内容协商方式是使用HTTP头。我们通常使用Accept来设置我们接受的返回结果的内容格式,用Accept-Charset来设置字符集,用Accept-Encoding来设置数据传输格式,用Accept-Language来设置语言。
使用URI模式进行内容协商
还有一种模式,就是将协商设置直接作为URI的一部分,将不同的返回视为不同的资源,比如/航班号/json来返回JSON格式的结果,用/航班号/atom来返回ATOM格式的结果。
正确的使用HTTP响应代码
作为API的设计者,正确的将API执行结果和失败原因用清晰简洁的方式传达给客户程序是十分关键的一步。 我们确实可以在HTTP的相应内容中描述是否成功,如果出错是因为什么, 然而, 这就意味着用户需要进行内容解析,才知道执行结果和错误原因。因此,HTTP响应代码可以保证客户端在第一时间用最高效的方式获知API运行结果,并采取相应动作。
转载,仅供参考,祝你愉快,满意请采纳。
⑼ 如何设计RESTful的API权限
RESTful的授权依靠框架就能解决 比如Jersey Spring,以及servlet容器等都提供授权机制;RESTful难的是认证,token一旦被劫持,授权就没有意义了。
⑽ RESTful API 怎么实现用户权限控制
本文是基于RESTful描述的,需要你对这个有初步的了解。
RESTful是什么?
Representational State Transfer,简称REST,是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。
REST比较重要的点是资源和状态转换,
所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。
而"状态转换",则是把对应的HTTP协议里面,四个表示操作方式的动词分别对应四种基本操作:
1. GET,用来浏览(browse)资源
2. POST,用来新建(create)资源
3. PUT,用来更新(update)资源
4. DELETE,用来删除(delete)资源。
资源的分类及操作
清楚了资源的概念,然后再来对资源进行一下分类,我把资源分为下面三类:
1. 私人资源 (Personal Source)
2. 角色资源 (Roles Source)
3. 公共资源 (Public Source)
"私人资源":是属于某一个用户所有的资源,只有用户本人才能操作,其他用户不能操作。例如用户的个人信息、订单、收货地址等等。
"角色资源":与私人资源不同,角色资源范畴更大,一个角色可以对应多个人,也就是一群人。如果给某角色分配了权限,那么只有身为该角色的用户才能拥有这些权限。例如系统资源只能够管理员操作,一般用户不能操作。
"公共资源":所有人无论角色都能够访问并操作的资源。
而对资源的操作,无非就是分为四种:
1. 浏览 (browse)
2. 新增 (create)
3. 更新 (update)
4. 删除 (delete)
角色、用户、权限之间的关系
角色和用户的概念,自不用多说,大家都懂,但是权限的概念需要提一提。
"权限",就是资源与操作的一套组合,例如"增加用户"是一种权限,"删除用户"是一种权限,所以对于一种资源所对应的权限有且只有四种。
角色与用户的关系:一个角色对应一群用户,一个用户也可以扮演多个角色,所以它们是多对多的关系。
角色与权限的关系:一个角色拥有一堆权限,一个权限却只能属于一个角色,所以它们是一(角色)对多(权限)的关系
权限与用户的关系:由于一个用户可以扮演多个角色,一个角色拥有多个权限,所以用户与权限是间接的多对多关系。
需要注意两种特别情况:
1. 私人资源与用户的关系,一种私人资源对应的四种权限只能属于一个用户,所以这种情况下,用户和权限是一(用户)对多(权限)的关系。
2. 超级管理员的角色,这个角色是神一般的存在,能无视一切阻碍,对所有资源拥有绝对权限,甭管你是私人资源还是角色资源。
数据库表的设计
角色、用户、权限的模型应该怎么样设计,才能满足它们之间的关系?
对上图的一些关键字段进行说明:
Source
name: 资源的名称,也就是其他模型的名称,例如:user、role等等。
identity: 资源的唯一标识,可以像uuid,shortid这些字符串,也可以是model的名称。
permissions : 一种资源对应有四种权限,分别对这种资源的browse、create、update、delete
Permission
source : 该权限对应的资源,也就是Source的某一条记录的唯一标识
action :对应资源的操作,只能是browse、create、update、delete四个之一
relation:用来标记该权限是属于私人的,还是角色的,用于OwnerPolicy检测
roles: 拥有该权限的角色
Role
users : 角色所对应的用户群,一个角色可以对应多个用户
permissions: 权限列表,一个角色拥有多项权利
User
createBy : 该记录的拥有者,在user标里,一般等于该记录的唯一标识,这一属性用于OwnerPolicy的检测,其他私有资源的模型设计,也需要加上这一字段来标识资源的拥有者。
roles : 用户所拥有的角色
策略/过滤器
在sails下称为策略(Policy),在java
SSH下称为过滤器(Filter),无论名称如何,他们工作原理是大同小异的,主要是在一条HTTP请求访问一个Controller下的action
之前进行检测。所以在这一层,我们可以自定义一些策略/过滤器来实现权限控制。
为行文方便,下面姑且允许我使用策略这一词。
*策略 (Policy) *
下面排版顺序对应Policy的运行顺序
SessionAuthPolicy:
检测用户是否已经登录,用户登录是进行下面检测的前提。
SourcePolicy:
检测访问的资源是否存在,主要检测Source表的记录
PermissionPolicy:
检测该用户所属的角色,是否有对所访问资源进行对应操作的权限。
OwnerPolicy:
如果所访问的资源属于私人资源,则检测当前用户是否该资源的拥有者。
如果通过所有policy的检测,则把请求转发到目标action。