1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
@Controller public class ArticleController { @RequestMapping (value = "/article/{category}/{id}" , method = RequestMethod.GET) public ModelAndView loadArticle( @PathVariable String category, @PathVariable int id, @RequestParam (value = "mode" , required = false ) String mode) { // ... } @RequestMapping (value = "/article" , method = RequestMethod.GET) public ModelAndView loadArticleCategories() { // ... } @RequestMapping (value = "/article" , method = RequestMethod.DELETE) public ModelAndView delArticleCategories() { // ... } @RequestMapping (value = "/addarticle" , method = RequestMethod.POST) public ModelAndView addArticleCategories(Category category) { // ... } @RequestMapping (value = "/addarticle/{name}" , method = RequestMethod.POST) public ModelAndView addArticleCategoriesForName( @PathVariable String name) { // ... } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
@Component ( "articleClient" ) public class ArticleClient { @Autowired protected RestTemplate restTemplate; @SuppressWarnings ( "unchecked" ) public List<Category> getCategories() { return restTemplate.getForObject(articleServiceUrl + "article" , List. class ); } public Article getArticle(String category, int id) { return restTemplate.getForObject(articleServiceUrl + "article/{category}/{id}" , Article. class , category, id); } @SuppressWarnings ( "unchecked" ) public void delCategories() { restTemplate.delete(articleServiceUrl + "article" ); } @SuppressWarnings ( "unchecked" ) public List<Category> postCategories() { Map<String, String> params = new HashMap<String, String>(); params.put( "name" , "jizhong" ); return restTemplate.postForObject(articleServiceUrl + "addarticle/{name}" , null , List. class , params); } } |
- HTTP GET: 获取资源
- HTTP PUT/POST: 创建/添加资源
- HTTP PUT: 修改资源
- HTTP DELETE: 删除资源
本文将介绍上述四种Request类型的使用,同时也会简略介绍HEAD与OPTIONS请求。
参考书籍:《RESTful Web Services》, Chapter 4, “The Resource-Oriented Architecture”
GET, PUT和DELETE
GET请求用于向Server端获取资源,而DELETE请求则用于删除Server端的某个资源。GET的Response一般包含资源的内容,而DELETE的Response可能包含一些状态信息(删除成功或者失败),也可能什么都不包含。 比如:GET /web/blog/3 这个请求会获取第三篇blog的内容,而DELETE /web/blog/3 这个请求则会删除第三篇blog。
PUT请求用于在Server端创建新的资源 (create),或者对已有资源进行修改 (modify)。PUT请求中一般会包含该新资源的内容。 比如:PUT /web/blog 这个请求会在Server端创建一个新的资源,资源名称是blog;而PUT /web/blog/3 这个请求则会修改第三篇blog(用新的内容来覆盖旧的)。
POST
POST请求也可用于在Server端创建新资源,但是在RESTful的世界里,POST请求被定义为创建“从属资源”(拥有父资源的资源) (add)。这话比较拗口,看一下例子可能会清晰很多:
在Server端没有/web/blog的情况下,使用PUT /web/blog请求可以在Server端创建blog资源。blog资源创建好之后,可以使用POST /web/blog来添加一篇新的blog文章,POST请求成功后,我们就拥有了/web/blog/1这个资源。假如当前已经有了三篇blog (/web/blog/1, /web/blog/2和/web/blog/3),那么POST /web/blog将在Server端添加第四篇blog文章(/web/blog/4) — 在这个场景中,/web/blog/1, /web/blog/2, /web/blog/3和/web/blog/4都是“从属资源”(拥有/web/blog这个父资源的资源)。
如何来判断某次Request涉及的资源是从属资源呢?除了从概念逻辑上判断外,还有一个简便的方法来判定:对于POST请求来说,将要被添加的“从属资源”是URI未知的 — 在POST /web/blog请求添加新的一篇blog文章的时候,client并不知道这会是第几篇blog,也不知道该blog创建后的URI是什么(/web/blog/35? 还是/web/blog/42?)。与此相反,PUT请求创建、修改资源的时候,client端清楚的知道对应的URI (PUT /web/blog可以创建blog资源;在/web/blog已经存在的情况下,PUT /web/blog可以修改blog资源的设置;而PUT /web/blog/3则可以对某一篇特定的blog文章进行修改)。
除了添加新的“从属资源”,POST请求还有一种应用场景:对某个特定资源增补内容(append)。比如,对于第三篇blog,在blog的最后,添加一段内容 (POST /web/blog/3)。
对于PUT和POST的区别,我们总结为:
PUT用于创建(Create)或修改(Modify),而POST用于添加(Add)或增补(Append)
根据上述总结可推论,在PUT和POST的属性之间,还有一个重要的区别:PUT是幂等的(Idempotent),而POST不是 — 同一个操作连续进行多次,对于PUT而言其效果与只进行一次相同,但对于POST而言,每一次操作都会对Server端产生影响。
HEAD和OPTIONS
HEAD请求用于获取某个资源的元数据(metadata)–比如,该资源是否存在,该资源的内容长度是多少等等。
OPTIONS请求用于获取某个资源所支持的Request类型,在OPTIONS请求的Response中会包含Allow头信息,比如:
Allow: GET HEAD
上述例子表示该资源只支持GET请求与HEAD请求。
值得注意的是,在OPTIONS请求中,不同的Request头信息会影响最终返回的Response结果。比如,在OPTIONS请求中加入正确的Authorization信息,得到的访问权限就可能更高。