[Rest] http的4个方法无法满足要求怎么办

steven_cheng 2009-08-07
rest是面向资源的架构,有名词属性。希望用http的4个方法来表示对资源的操作。
那有这样一个常见需求:对一个用户来讲,除了标准crud以外,还要提供,修改密码、锁定、解锁等修改操作。
我想到的有这样几个解决办法:
一个用户的url是/users/{userId}
1.url标明做的操作:
put /users/{userId}/{option}
比如,修改密码,option值为setpasswd
但是这样明显有rpc的样子,很别扭
还有什么办法?加请求头?
各位是怎么考虑这个问题的
ajax 2009-08-08
steven_cheng 写道
rest是面向资源的架构,有名词属性。希望用http的4个方法来表示对资源的操作。
那有这样一个常见需求:对一个用户来讲,除了标准crud以外,还要提供,修改密码、锁定、解锁等修改操作。
我想到的有这样几个解决办法:
一个用户的url是/users/{userId}
1.url标明做的操作:
put /users/{userId}/{option}
比如,修改密码,option值为setpasswd
但是这样明显有rpc的样子,很别扭
还有什么办法?加请求头?
各位是怎么考虑这个问题的



实际上,基于你上面给出的put /users/{userId}/{option},
你是人为的把option的值设置为一个动词,所以,你又在这个基础上说,它有rpc的样子。

你的url 模式我赞成,但是为什么不可以写成/usrs/{userId}/{password},而且这个url应该对应一个新的资源PasswordResource,如果请求的put方法,我就知道这个是客户端请求更改密码的。

ajax 2009-08-08
ajax 写道
steven_cheng 写道
rest是面向资源的架构,有名词属性。希望用http的4个方法来表示对资源的操作。
那有这样一个常见需求:对一个用户来讲,除了标准crud以外,还要提供,修改密码、锁定、解锁等修改操作。
我想到的有这样几个解决办法:
一个用户的url是/users/{userId}
1.url标明做的操作:
put /users/{userId}/{option}
比如,修改密码,option值为setpasswd
但是这样明显有rpc的样子,很别扭
还有什么办法?加请求头?
各位是怎么考虑这个问题的



实际上,基于你上面给出的put /users/{userId}/{option},
你是人为的把option的值设置为一个动词,所以,你又在这个基础上说,它有rpc的样子。

你的url 模式我赞成,但是为什么不可以写成/usrs/{userId}/{password},而且这个url应该对应一个新的资源PasswordResource,如果请求的put方法,我就知道这个是客户端请求更改密码的。




再罗嗦几句,实际上你上面提到的问题就是资源设计的问题。在应用REST之前,没有什么资源的概念,所以,在我们自己的架构中,有一些相近的功能方法都是集中在一个类里,例如,用户相关的操作:用户的新增、修改,删除,密码的创建,密码的修改,加锁、解锁。

所以,就有你提出的以上的问题,很多REST文章提到资源设计的问题,建议你看看我转的一篇文章,这篇文章就有你说的这种问题以及解决之法,看这里

 

steven_cheng 2009-08-09

      我觉得你的回复给了我比较大的启发。但我并不赞成你的具体解决方案。

     

      比如,重置密码/usrs/{userId}/{password},这个url就有问题。如果password是指旧密码,那你put以后会修改这个密码,那样就违反了put请求的幂等性。


      我倒是觉得你说的把password作为一个Resource挺有道理。这个资源的标识符,也应该是用户的id,也就是说,put /password/{userId},或者put /users/{userId}/password,后一个很像那个以前的rpc,只是把动词setpassword改成了名词password,而且也符合层次结构。正如你所说,“在应用REST之前,没有什么资源的概念”。rest的资源是名词属性的,是不是说,如果遇到这种情况,把动词变成名词即可。比如,我叫passwordsetting,lock(该死,这个词也是名词,呵呵,option也是既是动词也是名词)。

     

      我觉得ROA(面向资源的架构)应该和面向对象的设计是不冲突的。我们让user有方法lock、setPassword等等,其实不应该影响到Rest的资源表达这一层。至于事实上,你的Resource这个Class是怎么实现的,是否用option这个参数区分来做业务逻辑也是无所谓的。只是为了让资源符合可寻址性。

 
      我之所以觉得别扭,就是觉得一个Resouce应该可以get,而password、lock这样的资源无法get,所以觉得别扭。我想,一个只接受put请求的Resource也应该是符合Rest语义的吧。

     

      总结一下:
      以前我们之所以定义rpc解决方案,是因为方法没有统一的语义。而Rest有统一的语义,crud对应于post,get,put,delete。这个统一的语义能够解决我们绝大多数的问题。如果超出crud的操作,那就用一个名词,确切地讲应该是一个动名词定义这个Resource,并让它支持超出范围的逻辑。

       不知我说的是否对?

 

ajax 2009-08-10
steven_cheng 写道

      我觉得你的回复给了我比较大的启发。但我并不赞成你的具体解决方案。

     

      比如,重置密码/usrs/{userId}/{password},这个url就有问题。如果password是指旧密码,那你put以后会修改这个密码,那样就违反了put请求的幂等性。


      我倒是觉得你说的把password作为一个Resource挺有道理。这个资源的标识符,也应该是用户的id,也就是说,put /password/{userId},或者put /users/{userId}/password,后一个很像那个以前的rpc,只是把动词setpassword改成了名词password,而且也符合层次结构。正如你所说,“在应用REST之前,没有什么资源的概念”。rest的资源是名词属性的,是不是说,如果遇到这种情况,把动词变成名词即可。比如,我叫passwordsetting,lock(该死,这个词也是名词,呵呵,option也是既是动词也是名词)。

     

      我觉得ROA(面向资源的架构)应该和面向对象的设计是不冲突的。我们让user有方法lock、setPassword等等,其实不应该影响到Rest的资源表达这一层。至于事实上,你的Resource这个Class是怎么实现的,是否用option这个参数区分来做业务逻辑也是无所谓的。只是为了让资源符合可寻址性。

 
      我之所以觉得别扭,就是觉得一个Resouce应该可以get,而password、lock这样的资源无法get,所以觉得别扭。我想,一个只接受put请求的Resource也应该是符合Rest语义的吧。

     

      总结一下:
      以前我们之所以定义rpc解决方案,是因为方法没有统一的语义。而Rest有统一的语义,crud对应于post,get,put,delete。这个统一的语义能够解决我们绝大多数的问题。如果超出crud的操作,那就用一个名词,确切地讲应该是一个动名词定义这个Resource,并让它支持超出范围的逻辑。

       不知我说的是否对?

 

 

我还是建议你读一下那本《Restful Web Service》,我不是唯书论者,但是那本书上很多内容确实对REST的理解有很大的帮助。

 

我简单的说一下你提到这些问题:

 

我前面提到了,资源的设计很重要,我刚才看了一下我给出的URL,确实有问题,我原来想给出的是/users/{userId}/password,注意,没有{},这个还是有区别的。当然,你最终还是要根据你自己的业务以及相关的情况来设计适合你的资源。

 

另外我坚决不同意你说的让user有lock等其它的方法,这也是ROA里面很严格的强调的。必须是标准方法。就拿Restlet来说,即便是构造仿造的PUT和DELETE,那也是必须指定标准的方法,而不能随意指定。

 

password为什么不能Get,比如我的系统和你的系统相互通信,如果password在你的系统被改变了,那我就需要知道password变成什么?这个时候,我需要发送一个GET请求吧?我的理解,lock也一样,如果用户在我的系统登陆,这个时候,我需要发个get请求给你,问问,这个用户是否被锁,如果是被锁状态,那么我这边就登陆不进。话说回来,即使真的没有Get方法,比如CustomerResource,只有PUT,DELETE,没什么别扭的。

 

关于你最后的总结,我用一句话来概括,实际上也是那本书上写的:如果你不确定,就把它设计成资源吧!

 

 

 

 

 

 

 

teamlet 2010-02-10
http 1.1 规范的方法有:OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE和
CONNECT

如果这些方法不能满足需求,可以自己定义。
自己定义的方法只能自己用,因为这些方法是不规范的。在使用过程中,需要客户端开发者和服务器端的开发者协商方法的含义、处理的方法、请求的参数、返回的结果以及错误的定义。
deepthink 2010-04-29
Http Method 其实是有一个特殊的方法叫做 extension method ,我的做法是对SpringRouter 和 SpringFinder 做了一下扩展
使用的方法为

//ajax 代码

$.ajax({
		type:"TEST",
		contentType:'application/json',
		dataType:'json',
		url:'auth/user/123',
		success:function(xhr){
			$('#testJson').val(xhr.responseText);
		},
		
		error:function(xhr,textStatus){
			dotx.showError(textStatus);
		}
	});

// Resource 中的代码
public boolean allowTest() {
		return true;
	}

	public Representation proTest(Variant variant){
		return new JsonRepresentation("text = {result:\"oooo\"}");
	}


目前的测试已经通过,不知道能不能给你带来帮助
gaotianpu 2010-05-17
我会这样设计资源uri:

/users/{userid}/password
put,修改密码

/users/{userid}/lock
put,上锁
deldete,解锁
Global site tag (gtag.js) - Google Analytics