cxf restful 返回json不同版本,怎么返回不同值

PHP中Restful api 错误提示返回值实现思路
作者:SegmentFault
字体:[ ] 类型:转载 时间:
REST是Representational State Transfer的缩写,翻译为“表现层状态转化”。表现层其实就是资源,因此可以理解为“资源状态转化”。接下来通过本文给大家介绍Restful api 错误提示返回值实现思路,感兴趣的朋友一起学习吧
RESTful架构是一种流行的互联网软件架构,它结构清晰,符合标准,易于理解,扩展方便。
REST是Representational State Transfer的缩写,翻译为“表现层状态转化”。表现层其实就是资源,因此可以理解为“资源状态转化”。
网络应用上的任何实体都可以看作是一种资源,通过一个URI(统一资源定位符)指向它。
不管是微博还是淘宝,他们都有自己的错误返回值格式规范,以及错误代码说明,这样不但手机端用起来方便,给人的感觉也清晰明了,高大上。遇到问题先找母本,大公司的规范就是我们参照的母本。为此,我仿照了淘宝的错误返回值格式,根据微博错误代码制定的标准自定了自己的错误代码,然后在Restful api 上进行测试。下面我将实现思路以及测试结果分享给大家。
我利用抽象工厂模式去实现这样的一个错误返回值。选择这种模式是因为考虑到了这种模式可以提供一个创建一系列相关或相互依赖对象的接口,与我的需求很接近。
1、按这个路径common\hint,我新建了个error文件夹存放我的错误提示程序文件。这文件夹中主要有这几个文件:
2、Hint.php入口文件。定义一个抽象类,里边只写一个方法。
interface Hint {
function Error($_errors,$code);
3、Template.php 实现Hint这个接口。错误返回值的格式就在这里定义。
class Template implements Hint{
function Error($_errors,$code) {
if (empty($_errors)) {
print_r(json_encode([]));
$errors['error']['name'] = 'Not Found';
$errors['error']['message'] = $_
$errors['error']['error_code'] = $
print_r(json_encode($errors));
4、createMsg.php 再创建一个createMsg抽象类。将对象的创建抽象成一个接口。
interface createMsg {
function Msg();
5、用FactoryMsg 类去实现createMsg接口。返回实例化的Template。
class FactoryMsg implements createMsg{
function Msg() {
return new T
6、ErrorMsg.php 给Template里边的Error方法传参。
class ErrorMsg {
// 抽象工厂里的静态方法
public static function Info($_errors) {
$Factory = new FactoryM
$result = strstr($_errors,Yii::t('yii','Not exist')); //数据不存在 20001
$result1 = strstr($_errors,Yii::t('yii','Null')); //参数不能为空 20002
$result2 = strstr($_errors,Yii::t('yii','Fail')); //新增、更新、删除失败 20003
$result3 = strstr($_errors,Yii::t('yii','Not right')); //XX不正确 20004
$result4 = strstr($_errors,Yii::t('yii','Robc')); //XX无权限 20005
//数据不存在 20001
if(!empty($result)){
$M = $Factory-&Msg();
$M-&Error($_errors,'20001');
//参数不能为空 20002
if(!empty($result1)){
$M = $Factory-&Msg();
$M-&Error($_errors,'20002');
//新增、更新、删除失败 20003
if(!empty($result2)){
$M = $Factory-&Msg();
$M-&Error($_errors,'20003');
//XX不正确 20004
if(!empty($result3)){
$M = $Factory-&Msg();
$M-&Error($_errors,'20004');
//XX无权限 20005
if(!empty($result4)){
$M = $Factory-&Msg();
$M-&Error($_errors,'20005');
//默认类型 21000
$M = $Factory-&Msg();
$M-&Error($_errors,'21000');
7、调用方式。
use common\hint\error\ErrorM
ErrorMsg::Info(Yii::t('yii','failure'));
8、测试结果。
"error": {
"name": "Not Found",
"message": "操作失败",
"error_code": "20003"
完成。整个实现过程我采用语言包的形式,这样有利于后期多语言的切换。
1、采用这种字符串模糊搜索很泛,无法达到具体错误类型返回对应具体代码的要求。如有更好的建议,欢迎大家提议。
$result = strstr($_errors,Yii::t('yii','Not exist'));
2、实现过程中没有考虑到今后多语言切换的问题,然后直接用传统的方式传提示语。比如:ErrorMsg::Info("操作失败");这样是无法实现多语言切换的。建议大家用语言包的方式传参。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具966,690 七月 独立访问用户
语言 & 开发
架构 & 设计
文化 & 方法
您目前处于:
RESTful HTTP的实践
RESTful HTTP的实践
Gregor Roth
注意:,500+CTO技聚重新定义技术领导力!
相关厂商内容
相关赞助商
QCon全球软件开发大会上海站,日-22日,上海宝华万豪酒店,!
REST并没有创造新的技术,组件或服务,隐藏在RESTful HTTP背后的理念是使用Web的现有特征和能力。RESTful
HTTP定义了如何更好地使用现有Web标准中的一些准则和约束。
资源是REST中最关键的抽象概念,它们是能够被远程访问的应用程序对象。一个资源就是一个标识单位,任何可以被访问或被远程操纵的东西都可能是一个资源。资源可以是静态的,也就是该资源的状态永远不会改变。相反,某些资源的状态可能随着时间推移呈现很大的可变性。这两种类型的资源都是有效的。
图1中所显示的这些类都能被很容易地映射成资源。面向对象设计者不容易理解把实体类(如Hotel或者Room)映射成资源,同样他们也不太理解从控制类(如coordination,事务和某个类的控制类)到资源的映射。
图1:分析模型的例子
分析模型是识别资源的一个非常好的&切入点&。然而,并非只能进行1对1映射,比如,
&Hotel&.listOccupancy()操作也可以被建模成资源。此外,也有可能某些资源只表示实体的某一部分。资源设计的主要驱动力是网络因素而不是对象模型。
任何重要的资源都应该能够通过一个唯一的标识被访问。RESTful
HTTP使用URI来识别资源。URI提供了Web通用的识别机制,它包含了客户端直接与被引用的资源进行交互时需要的所有信息。
如何命名资源标识?
虽然RESTful
HTTP并没有明确指出如何构造一个URI路径,但实际上经常被使用的是一些特定的命名模式。URI命名模式有助于应用程序调试和跟踪,通常一个URI包含资源类型及其后面用于定位特定资源的标识。这样的URI不包括指定业务操作的动词(verb),而只用于定位资源。图中a1给出了Hotel资源的一个示例,同一个Hotel资源也可以通过URI(a2)访问。同一资源可以被多个URI引用。
(a1) http://localhost/hotel/656bcee2-28d2-404b-891b
(a2) http://127.0.0.1/hotel/656bcee2-28d2-404b-891b
(b) http://localhost/hotel/656bcee2-28d2-404b-891b/Room/4
(c) http://localhost/hotel/656bcee2-28d2-404b-891b/Reservation/15
(d) http://localhost/hotel/656bcee2-28d2-404b-891b/Room/4/Reservation/15
(e) http://localhost/hotel/656bcee2-28d2-404b-891b/Room/4/Reservation/15v7
(f) http://localhost/hotel/656bcee2-28d2-404b-891bv12
图2:资源寻址的例子
URI也可以被资源用来在资源表示(representation)之间建立关联。例如,Hotel表示通过URI去引用已分配的Room资源,而不是使用普通的RoomID。使用普通的ID会强制调用者通过对资源的访问去构造URI,而调用者如果没有主机名和基础URI路径等上下文信息是无法访问到该资源的。
超链接常被客户端用于资源导航。RESTful
API是超文本驱动的,这表示客户端通过获得一个Hotel表示,就能够导航到已分配的Room表示和Reservation表示。
在实践中,图1所示的这些类经常被映射成某种业务对象,这意味着在业务对象的整个生命周期中URI将保持不变。如果要创建一个新资源,则要为之分配一个新的URI。而一旦这个新资源被删除,相应的URI则跟着失效。如图2中的(a),(b),(c)和(d)就是这种标识的例子。另一方面,URI也可以用来引用资源快照,比如(e)和(f)就是对这类快照的引用,其URI中包含了一个版本标识。
URI还可以定位子资源,如示例中的(b),(c),(d)和(e)。通常,被聚集的对象会被映射成子资源,如Room是被Hotel聚集的。被聚集的对象通常没有自己的生命周期,如果它的父对象被删除,所有的被聚集对象也跟着被删除。
然而,如果一个子资源可以从一个父资源移动到另一个父对象,
那么在它的URI中就不应该包含其父资源的标识。比如图1中的Reservation资源,它就可以被分配给另一个Room资源。如果一个Reservation资源的URI包含了其父资源Room的标识,如(d)所示,则当Room实例标识改变时,如果该Reservation资源又被另一个资源引用的话,这就会出问题。为了避免无效的URI,Reservation应该通过(c)这样的方式进行寻址。
通常,资源的URI是由服务器控制的。客户端访问资源时并不需要理解资源的URI命名空间结构。比如,使用(c)和(d)两个URI结构对客户端而言具有效果相同。
统一资源接口
为了简化整体系统架构,REST架构风格包含了统一接口的概念。统一接口包含一组受限的良定义的操作,由它们进行资源的访问和操作。不论什么资源,都使用相同的接口。客户端与Hotel,Room或CreditScore等资源交互时使用的接口是一样的。统一接口独立于资源的URI,并且也不需要类似IDL的文件去描述可用的操作。
HTTP的接口非常流行且广为使用。它包含标准的HTTP方法如GET,PUT和POST(浏览器使用它发出请求并提取页面)。不幸的是,很多开发者认为实现RESTful应用就是用一种直接使用HTTP的方式,这种理解是错误的。举个例子,HTTP方法的实现必须要遵循HTTP规范的,而通过GET方法创建或修改对象是不遵守HTTP规范的。
应用统一接口
关于何时以及如何使用不同的HTTP动词(verb),在Fielding的论文中没有任何表格、列表或其他方式的描述。对于大部分方法,如GET或
DELETE,通过阅读HTTP规范就能清楚其含义,而对于POST和部分更新,就不那么容易了。在实践中,对资源进行部分更新有好几种方法,下文将有详细介绍。
表1列出了大部分重要的方法GET,DELETE,PUT和POST的典型用法:
典型状态码
- 获取表示
- 变更时获取表示(缓存)
200(OK) - 表示已在响应中发出
204(无内容) - 资源有空表示
301(Moved Permanently) - 资源的URI已被更新
303(See Other) - 其他(如,负载均衡)
304(not modified)- 资源未更改(缓存)
400 (bad request)- 指代坏请求(如,参数错误)
404 (not found)- 资源不存在
406 (not acceptable)- 服务端不支持所需表示
500 (internal server error)- 通用错误响应
503 (Service Unavailable)- 服务端当前无法处理请求
- 删除资源
200 (OK)- 资源已被删除
301 (Moved Permanently)- 资源的URI已更改
303 (See Other)- 其他,如负载均衡
400 (bad request)- 指代坏请求t
404 (not found)- 资源不存在
409 (conflict)-
500 (internal server error)- 通用错误响应
503 (Service Unavailable)-
服务端当前无法处理请求
- 用客户端管理的实例号创建一个资源
- 通过替换的方式更新资源
- 如果未被修改,则更新资源(乐观锁)
200 (OK)- 如果已存在资源被更改
201 (created)-
如果新资源被创建
301(Moved Permanently)- 资源的URI已更改
303 (See Other)- 其他(如,负载均衡)
400 (bad request)- 指代坏请求
404 (not found)- 资源不存在
406 (not acceptable)- 服务端不支持所需表示/p&
409 (conflict)- 通用冲突
412 (Precondition Failed)-
前置条件失败(如执行条件更新时的冲突)
415 (unsupported media type)- 接受到的表示不受支持
500 (internal server error)- 通用错误响应
503 (Service Unavailable)- 服务当前无法处理请求
- 使用服务端管理的(自动产生)的实例号创建资源
- 创建子资源
- 部分更新资源
- 如果没有被修改,则不过更新资源(乐观锁)
200(OK)- 如果现有资源已被更改
201(created)- 如果新资源被创建
202(accepted)-
已接受处理请求但尚未完成(异步处理)
301(Moved Permanently)- 资源的URI被更新
303(See Other)- 其他(如,负载均衡)
400(bad request)- 指代坏请求
404 (not found)- 资源不存在
406 (not acceptable)-
服务端不支持所需表示
409 (conflict)- 通用冲突
412 (Precondition Failed)-
前置条件失败(如执行条件更新时的冲突)
415 (unsupported media type)- 接受到的表示不受支持
500 (internal server error)- 通用错误响应
503 (Service Unavailable)-
服务当前无法处理请求
表1:统一接口示例
对资源的操纵永远是通过其表示实现的。资源可能永远不会在网络中传输,相反,传输的是资源的表示。资源的表示包括数据和描述数据的元数据,例如,HTTP头&Content-Type&
就是这样一个元数据属性。
图3展示了如何使用Java获取表示。该例程使用了Java HTTP库xLightweb中的HttpClient类,这个库由作者本人维护。
HttpClient httpClient = new HttpClient();
IHttpRequest request = new GetRequest(centralHotelURI);
IHttpResponse response = httpClient.call(request);
图3:获取表示的Java例程
通过调用HTTP客户端的call方法,一个访问Hotel资源表示的HTTP请求就被发送出去。返回的表示如图4所示,它也包含了用于指示实体主体的多媒体类型的Content-Type头。
GET /hotel/656bcee2-28d2-404b-891b HTTP/1.1
Host: localhost
User-Agent: xLightweb/2.6
HTTP/1.1 200 OK
Server: xLightweb/2.6
Content-Length: 277
Content-Type: application/x-www-form-urlencoded
classification=Comfort&name=Central&RoomURI=http%3A%2F%2Flocalhost%2Fhotel%2F
656bcee2-28d2-404b-891b%2FRoom%2F2&RoomURI=http%3A%2F%2Flocalhost%2Fhotel%2F6
56bcee2-28d2-404b-891b%2FRoom%2F1
图4:RESTful HTTP交互
如何支持特定表示?
为了避免传输很大的数据集,有时应该接收表示属性一个子集。在实现时,用于指定部分属性的一种方式就是支持对指定属性的寻址,如图5所示。
GET /hotel/656bcee2-28d2-404b-891b/classification HTTP/1.1
Host: localhost
User-Agent: xLightweb/2.6
Accept: application/x-www-form-urlencoded
HTTP/1.1 200 OK
Server: xLightweb/2.6
Content-Length: 26
Content-Type: application/x-www-form- charset=utf-8
classification=Comfort
图5:属性过滤
图5中所示的GET调用只请求了一个属性(classification),如果要请求多个属性,所请求的属性要用逗号隔开,如图6所示。
GET /hotel/656bcee2-28d2-404b-891b/classification,name HTTP/1.1
Host: localhost
User-Agent: xLightweb/2.6
Accept: application/x-www-form-urlencoded
HTTP/1.1 200 OK
Server: xLightweb/2.6
Content-Length: 43
Content-Type: application/x-www-form- charset=utf-8
classification=Comfort&name=Central
图6:多属性过滤
确定所需属性的另一种方法是使用查询参数,通过它列出所请求的属性,如图7所示。查询参数将用于定义查询条件以及更复杂的过滤或查询准则。
GET /hotel/656bcee2-28d2-404b-891b?reqAttr=classification&reqAttr=name HTTP/1.1
Host: localhost
User-Agent: xLightweb/2.6
Accept: application/x-www-form-urlencoded
HTTP/1.1 200 OK
Server: xLightweb/2.6
Content-Length: 43
Content-Type: application/x-www-form- charset=utf-8
classification=Comfort&name=Central
图7:查询字符串
在上述例子中,服务器总是返回以application/x-www-form-urlencoded编码的媒体类型的表示。该媒体类型将实体编码成键值对列表。键值方法理解起来很容易,但缺点是,它不适用与更加复杂的数据结构。此外,这种媒体类型不支持标量数据类型的绑定,如Integer,Boolean,Date等。基于这个原因,通常使用XML,JSON或Atom来表征资源(JSON也没有定义Data类型的绑定)
HttpClient httpClient = new HttpClient();
IHttpRequest request = new GetRequest(centralHotelURI);
request.setHeader(&Accept&, &application/json&);
IHttpResponse response = httpClient.call(request);
String jsonString = response.getBlockingBody().readString();
JSONObject jsonObject = (JSONObject) JSONSerializer.toJSON(jsonString);
HotelHotel= (Hotel) JSONObject.toBean(jsonObject, Hotel.class);
图8:请求JSON表示
通过设置&Accept&请求头,客户端就可以请求指定的表示编码。图8展示了如何对application/json类型的表示的请求。JSONlib将把图9中显示的返回响应消息映射成Hotel
GET /hotel/656bcee2-28d2-404b-891b HTTP/1.1
Host: localhost
User-Agent: xLightweb/2.6
Accept: application/json
HTTP/1.1 200 OK
Server: xLightweb/2.6
Content-Length: 263
Content-Type: application/ charset=utf-8
{&classification&:&Comfort&,
&name&:&Central&,
&RoomURI&:[&http://localhost/hotel/656bcee2-28d2-404b-891b/Room/1&,
&http://localhost/hotel/656bcee2-28d2-404b-891b/Room/2&]}
图9:JSON表示
如何报告错误?
当服务器不支持所请求的表示时怎么办?图10展示了一个请求XML表示资源的HTTP交互,若服务器不支持这种表示,它将返回一个HTTP
406响应,表示拒绝处理该请求。
GET /hotel/656bcee2-28d2-404b-891b HTTP/1.1
Host: localhost
User-Agent: xLightweb/2.6
Accept: text/xml
HTTP/1.1 406 No match for accept header
Server: xLightweb/2.6
Content-Length: 1468
Content-Type: text/ charset=iso-8859-1
&meta http-equiv=&Content-Type& content=&text/ charset=ISO-8859-1&/&
&title&Error 406 No match for accept header&/title&
&h2&HTTP ERROR: 406&/h2&&pre&No match for accept header&/pre&
图10:不支持的表示
RESTful HTTP服务端程序必须根据HTTP规范返回状态码。状态码的第一个数字标识返回类型,1xx表示临时响应,2xx表示成功响应
,3xx代表转发,4xx表示客户端错误,5xx代表服务端错误。使用错误的响应码,或者总返回200响应,并在消息主体中包含特定应用程序的响应,这两种做法都是不好的实践。
客户代理和中介也要分析返回码。例如,xLightweb
HttpClient默认会把持久的HTTP连接保存在连接池中,当一个HTTP交互完成时,持久化HTTP连接就应返回到内部连接池已备重用。而只有完好的连接才能被放回连接池,比如,若返回码是5xx,那该连接就不会重回连接池了。
有时某些特定的客户端要求更简洁的返回码。一种方法是增加一个HTTP头&X-Header&,用它来详细描述HTTP状态码。
POST /Guest/ HTTP/1.1
Host: localhost
User-Agent: xLightweb/2.6
Content-Length: 94
Content-Type: application/x-www-form-urlencoded
zip=30314&lastName=Gump&street=42+Plantation+Street&firstName=Forest&country=US&
city=Baytown&state=LA
HTTP/1.1 400 Bad Request
Server: xLightweb/2.6
Content-Length: 55
Content-Type: text/ charset=utf-8
X-Enhanced-Status: BAD_ADDR_ZIP
AddressException: bad zip code 99566
图11:附加状态码
通常只有在进行编程问题诊断时才需要详细的错误码。尽管比起详细的错误码,HTTP状态码的描述性总是要差很多,但是在大多数情况下,它们对于客户端正确处理问题已经足够了。另一种方法是在响应主体中包含详细的错误码。
PUT还是POST?
较之流行的RPC方式,HTTP方法不仅仅在方法名上有所不同,而且HTTP方法中的某些属性(如幂等性,安全性等)也扮演着重要的角色。不同的HTTP方法的幂等性和安全性属性也是不同的。
HttpClient httpClient = new HttpClient();
String[] params = new String[] { &firstName=Forest&,
&lastName=Gump&,
&street=42 Plantation Street&,
&zip=30314&,
&city=Baytown&,
&state=LA&,
&country=US&};
IHttpRequest request = new PutRequest(gumpURI, params);
IHttpResponse response = httpClient.call(request);
图12:使用PUT方法
如图12和13所示,使用PUT操作来创建一个新的Guest资源。PUT方法将封装好的资源存放在Request-URI之下。该URI是由客户端决定的,当Request-URI指向某现存资源时,该资源将被新资源替换。基于该原因,PUT方法一般用于创建新资源或更新现有资源。然而,通过使用PUT,资源的整个状态都会被改变,若一个请求只需要修改zip域,它不得不包含该资源的其他域,如
firstName,city等。
PUT Hotel/guest/bc45-9aa3-3f22d HTTP/1.1
Host: localhost
User-Agent: xLightweb/2.6
Content-Length: 94
Content-Type: application/x-www-form-urlencoded
zip=30314&lastName=Gump&street=42+Plantation+Street&firstName=Forest&country=US&
city=Baytown&state=LA
HTTP/1.1 200 OK
Server: xLightweb/2.6
Content-Length: 36
Content-Type: text/ charset=utf-8
Location: http://localhost/guest/bc45-9aa3-3f22d
The guest resource has been updated.
图13:HTTP PUT交互
PUT方法是幂等的,幂等性意味着对于一个成功执行的请求,不管其执行多少次,其结果都是一致的。也就是说,只要你愿意,你可以用PUT方法对Hotel资源进行任意次更新,其结果都一样。如果两个PUT方法同时发生,那么只有其中之一会赢得最后的胜利并决定资源的最终状态。删除操作也是幂等的,如果一个PUT方法和DELETE方法同时发生,那么资源或者被更新,或者被删除,而不可能停留在某个中间状态。
如果你不确定是PUT还是DELETE被成功执行,并且没有得到状态码409 (Conflict)或者 417 (Expectation
Failed)的话,那么就重新执行一遍。而不需要附加的可靠性协议来避免重复请求,因为通常重复的请求不会有任何影响。
上述描述对于POST方法就不适用了,因为POST方法不是幂等的,若要两次执行同一个POST请求那就要注意了。POST方法所缺失的幂等性就解释了为什么当你每次重新发送POST请求时浏览器总是弹出警告。POST方法用于创建资源,而不需要由客户端指定实例id,图14展示了通过POST方法创建一个Hotel资源的HTTP交互过程。通常,客户端使用只包含基路径和资源类型名的URI来发送POST请求。
POST /HotelHTTP/1.1
Host: localhost
User-Agent: xLightweb/2.6
Content-Length: 35
Content-Type: application/x-www-form- charset=utf-8
Accept: text/plain
classification=Comfort&name=Central
HTTP/1.1 201 Created
Server: xLightweb/2.6
Content-Length: 40
Content-Type: text/ charset=utf-8
Location: http://localhost/hotel/656bcee2-28d2-404b-891b
the Hotelresource has been created
图14:HTTP POST交互(创建)
POST方法也经常用于更新资源的部分内容,比如,如果我们要通过发送仅包含classification属性的PUT请求去更新Hotel资源的话,这就是违反HTTP的,但是用POST方法则没有问题。POST方法既不是幂等的,也不是安全的。图15展示了一个执行部分更新的POST方法。
POST /hotel/0ae526f0-9c3d HTTP/1.1
Host: localhost
User-Agent: xLightweb/2.6
Content-Length: 19
Content-Type: application/x-www-form- charset=utf-8
Accept: text/plain
classification=First+Class
HTTP/1.1 200 OK
Server: xLightweb/2.6
Content-Length: 52
Content-Type: text/ charset=utf-8
the Hotelresource has been updated (classification)
图15: HTTP POST交互 (更新)
还可以使用PATCH方法来进行部分更新,PATCH方法是对资源进行部分更新的一个特殊方法。一个PATCH请求包含一个补丁文档,它将应用于由Request-URI所指定的资源。然而PATCH的RFC规范还在草稿中。
使用HTTP缓存
为提高扩展性并降低服务端负载,
RESTful的HTTP应用程序可以利用WEB基础设施的缓存机制。HTTP已经意识到缓存是WEB基础设施必不可少的一部分,比如,HTTP协议定义了专门的消息头来支持缓存。如果服务端设置了这个头,客户端(如HTTP客户端或Web缓存代理)就能够有效地支持缓存策略。
HttpClient httpClient = new HttpClient();
httpClient.setCacheMaxSizeKB(500000);
IHttpRequest request = new GetRequest(centralHotelURI + &/classification&);
request.setHeader(&Accept&, &text/plain&);
IHttpResponse response = httpClient.call(request);
String classification = response.getBlockingBody.readString();
// ... sometime later re-execute the request
response = httpClient.call(request);
classification = response.getBlockingBody.readString();
图16:客户端缓存交互
图16显示了一个重复的GET调用。通过设置最大缓存大小的值&0激活了HttpClient的缓存功能。如果响应消息中包含了刷新头,比如Expires或Cache-Control:
max-age,该响应就会被HttpClient缓存。这些头指明了关联的表示可以保鲜的时间为多久。如果在一段时间内发出了相同的请求,那么HttpClient就会使用缓存为这些请求提供服务,而不需要重复进行网络调用。在网络上总共只有一次HTTP交互,如图17所示。诸如WEB代理之类的缓存中介也实现了相同的功能,而且该缓存还可以在不同客户端之间共享。
GET /hotel/656bcee2-28d2-404b-891b/classification HTTP/1.1
Host: localhost
User-Agent: xLightweb/2.6
Accept: text/plain
HTTP/1.1 200 OK
Server: xLightweb/2.6
Cache-Control: public, max-age=60
Content-Length: 26
Content-Type: text/ charset=utf-8
图17:包含过期头的HTTP响应
过期模型在静态资源上很好用,可是,对于动态资源(资源状态经常改变且无法预测)则不尽相同。HTTP通过验证头,如Last-Modified以及ETag来支持动态资源的缓存。与过期模型相比,验证模型没有节省网络调用。但是,当执行带条件的GET方法时它会对昂贵的操作节约网络传输,图
18(2.request)显示了带条件的GET操作,它带有一个额外的Last-Modified头,这个头包含了缓存对象最后修改日期。如果该资源未被更改,服务端将会返回一个304
(Not Modified) 响应。
1. REQUEST:
GET /hotel/656bcee2-28d2-404b-891b/Reservation/1 HTTP/1.1
Host: localhost
User-Agent: xLightweb/2.6
Accept: application/x-www-form-urlencoded
1. RESPONSE:
HTTP/1.1 200 OK
Server: xLightweb/2.6
Content-Length: 252
Content-Type: application/x-www-form-urlencoded
Last-Modified: Mon, 01 Jun :18 GMT
from=T09%3A49%3A09.718&to=T09%3A49%3A09.718&guestURI=
http%3A%2F%2Flocalhost%2Fguest%2Fbc45-9aa3-3f22d&RoomURI=http%3A%2F%2F
localhost%2Fhotel%2F656bcee2-28d2-404b-891b%2FRoom%2F1
2. REQUEST:
GET /hotel/0ae526f0-9c3d/Reservation/1 HTTP/1.1
Host: localhost
User-Agent: xLightweb/2.6
Accept: application/x-www-form-urlencoded
If-Modified-Since: Mon, 01 Jun :18 GMT
2. RESPONSE:
HTTP/1.1 304 Not Modified
Server: xLightweb/2.6
Last-Modified: Mon, 01 Jun :18 GMT
图18:基于验证的缓存
不要在服务端存储应用状态
HTTP的交互必须是无状态的,这表明每一次请求要包含处理该请求所需的一切信息。客户端负责维护应用状态。RESTful服务端不需要在请求间保留应用状态,服务端负责维护资源状态而不是应用状态。服务端和中介能够理解独立的请求和响应。Web缓存代理拥有一切正确处理请求所需的信息并管理它的缓存。
这种无状态的方法是实现高扩展和高可用应用的基本原则。通常无状态使得每一个客户请求可以由不同的服务器来响应,当流量增加时,新的服务器可以加进来,而如果某个服务器失败,它也可以从集群中移除。若要了解关于负载均衡以及故障恢复方面的更详细信息,请参考这篇文章。
对non-CRED操作的支持
开发者经常想了解如何将non-CRUD(Create-Read-Update-Delete)操作映射到资源。显然,Create、Read、Update和Delete等操作能够很容易地映射到资源的方法。然而,
RESTful HTTP还不仅限于面向CRUD的应用。
图19: RESTful HTTP资源
就如图19所示的creditScoreCheck而言,它提供了一个non-CRUD操作creditScore(...),该操作接受一个address,计算出score并返回。这样的操作可以通过CreditScoreResource实现,该资源代表着计算的返回。图20展示了一个GET方法,它传入address,然后提取CreditScoreResource表示,查询参数被用来指定CreditScoreResource。GET方法是安全的,并且可缓存,所提它很适用于CreditScore
Check的creditScore(...)方法的非功能性行为。计算的结果可以缓存一段时间,如图20所示,响应包含了一个缓存头,它通知客户端和中介执行响应缓存。
GET /CreditScore/?zip=30314&lastName=Gump&street=42+Plantation+Street&
firstName=Forest&country=US&city=Baytown&state=LA HTTP/1.1
Host: localhost
User-Agent: xLightweb/2.6
Accept: application/x-www-form-urlencoded
HTTP/1.1 200 OK
Server: xLightweb/2.6
Content-Length: 31
Content-Type: application/x-www-form-urlencoded
Cache-Control: public, no-transform, max-age=300
scorecard=Excellent&points=92
图20:Non-CRUD HTTP GET交互
上述例子还显示了GET方法的局限性。尽管HTTP规范并没有指定URL的最大长度,但是实际上客户端,中介以及服务端对URL的长度都有限制。基于此,通过GET的查询参数发送一个很大的实体可能会因为中介和服务器对URL长度的限制而失败。
另一解决方法是使用POST方法,如果作了设置,它也是可缓存的。如图21所示,第一个POST请求的结果是创建了一个虚拟资源CreditScoreResource。输入的address数据用text/card这个mime类型进行编码,在服务端计算得到score之后,它发回一个201(created)响应,该响应包含着所创建的CreditScoreResource资源的URI。
示例中还展示了如果进行了设定,POST响应也可以被缓存。通过一个GET请求就能够取到计算结果。GET响应也包含一个缓存控制头,如果客户端紧接着重新执行这两次请求,那么它们都可由缓存进行响应。
1. REQUEST:
POST /CreditScore/ HTTP/1.1
Host: localhost
User-Agent: xLightweb/2.6
Content-Length: 198
Content-Type: text/x-vcard
Accept: application/x-www-form-urlencoded
BEGIN:VCARD
VERSION:2.1
FN:Forest Gump
ADR;HOME:;;42 Plantation St.;BLA;30314;US
LABEL;HOME;ENCODING=QUOTED-PRINTABLE:42 Plantation St.=0D=0A30314 Baytown=0D=0ALA US
1. RESPONSE:
HTTP/1.1 201 Created
Server: xLightweb/2.6
Cache-Control: public, no-transform, max-age=300
Content-Length: 40
Content-Type: text/ charset=utf-8
Location: http://localhost/CreditScore/l00005c
the credit score resource has been created
2. REQUEST:
GET /CreditScore/l00005c HTTP/1.1
Host: localhost
User-Agent: xLightweb/2.6
2. RESPONSE:
HTTP/1.1 200 OK
Server: xLightweb/2.6
Content-Length: 31
Content-Type: application/x-www-form-urlencoded
Cache-Control: public, no-transform, max-age=300
scorecard=Excellent&points=92
图21: Non-CRUD HTTP POST交互
还有其他不同的实现方式。比如不返回201响应,而返回301(Moved
Permanently)转发响应。该响应缺省是可缓存的。其他避免二次请求的方法是在201响应中增加一个新创建的CreditScoreResource资源的表示。
大多数SOA架构(如SOAP或CORBA)都试图映射如图1所示的类模型,或多或少是一对一的远程访问。通常,这些SOA架构的比较多地关注在编程语言对象的透明映射上,这种映射很容易理解,且易于跟踪。可是,它们把对分布性和扩展性等方面的关注排在第二位。
相反,REST架构风格的最主要驱动是分布性和扩展性。RESTful HTTP接口的设计是由网络因素而非编程语言的绑定驱动的。 RESTful
HTTP也没有试图去封装很那些难隐藏的因素,如网络延迟,网络健壮性以及网络带宽等。
RESTful HTTP应用用一种直接的方式使用HTTP协议,而不需任何抽象层,也不存在REST指定的数据域,如错误域,安全令牌域等。RESTful
HTTP应用只使用WEB的固有能力。设计RESTful
HTTP的接口意味着远程结构的设计者必须在HTTP协议上进行思考。这通常增加了开发周期中额外步骤。
然而,RESTful HTTP使得应用程序实现具有高扩展性,更健壮。特别是为很大用户群提供Web应用的公司,如
WebMailing或SocialNetworking的应用就能从REST架构风格中获益。通常,这些应用要更快更高地扩展,而且,这些公司通常在一些低预算的基础设施(基于广泛使用的标准组件和软件之上)上运行应用。
Gregor Roth,xLightweb HTTP库的作者。在United
Internet组织担任软件架构师,该组织是最重要的欧洲因特网服务提供商,其产品有GMX, 1&1, and
Web.de等。他感兴趣的领域包括软件和系统架构、企业架构管理、面向对象设计、分布式计算和开发方法论等。
查看英文原文:。
感谢对本文的审校。
给InfoQ中文站投稿或者参与内容翻译工作,请邮件至。也欢迎大家加入到中与我们的编辑和其他读者朋友交流。
Author Contacted
告诉我们您的想法
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
non-CRUD操作部分讲的还是不够啊.
Colder Xihk
Restful HTTP in practice
wang zhaoyu
Re: non-CRUD操作部分讲的还是不够啊.
好文章,但是翻译不好,读起来很费劲
wang demon
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
赞助商链接
InfoQ每周精要
通过个性化定制的新闻邮件、RSS Feeds和InfoQ业界邮件通知,保持您对感兴趣的社区内容的时刻关注。
架构 & 设计
文化 & 方法
<及所有内容,版权所有 &#169;
C4Media Inc.
服务器由 提供, 我们最信赖的ISP伙伴。
北京创新网媒广告有限公司
京ICP备号-7
注意:如果要修改您的邮箱,我们将会发送确认邮件到您原来的邮箱。
使用现有的公司名称
修改公司名称为:
公司性质:
使用现有的公司性质
修改公司性质为:
使用现有的公司规模
修改公司规模为:
使用现在的国家
使用现在的省份
Subscribe to our newsletter?
Subscribe to our industry email notices?

我要回帖

更多关于 restful api 返回json 的文章

 

随机推荐