关于restful:搭建-Restful-Web-服务

33次阅读

共计 8925 个字符,预计需要花费 23 分钟才能阅读完成。

1. 了解 REST

  REST 全称是 Representational State Transfer,中文意思是表征性状态转移。它首次呈现在 2000 年 Roy Fielding 的博士论文中,Roy Fielding 是 HTTP 标准的次要编写者之一。值得注意的是 REST 并没有一个明确的规范,而更像是一种设计的格调。如果一个架构合乎 REST 的约束条件和准则,咱们就称它为 RESTful 架构。

  实践上 REST 架构格调并不是绑定在 HTTP 上,只不过目前 HTTP 是惟一与 REST 相干的实例。

1.1. REST 准则

  • 资源 可通过目录构造款式的 URIs 裸露
  • 表述 能够通过 JSON 或 XML 表白的数据对象或属性来传递
  • 音讯 应用对立的 HTTP 办法(例如:GET、POST、PUT 和 DELETE)
  • 无状态 客户端与服务端之间的交互在申请之间是无状态的,从客户端到服务端的每个申请都必须蕴含了解申请所必须的信息

    1.2. HTTP 办法

      应用 HTTP 将 CRUD(create, retrieve, update, delete < 创立、获取、更新、删除—增删改查 >)操作映射为 HTTP 申请。如果依照 HTTP 办法的语义来裸露资源,那么接口将会领有安全性和幂等性的个性,例如 GET 和 HEAD 申请都是平安的,无论申请多少次,都不会扭转服务器状态。而 GET、HEAD、PUT 和 DELETE 申请都是幂等的,无论对资源操作多少次,后果总是一样的,前面的申请并不会产生比第一次更多的影响。

    1.2.1. GET

  • 平安且幂等
  • 获取信息

    1.2.2. POST

  • 不平安且不幂等
  • 应用申请中提供的实体执行操作,可用于创立资源或更新资源

    1.2.3. PUT

  • 不平安但幂等
  • 应用申请中提供的实体执行操作,可用于创立资源或更新资源

    1.2.4. DELETE

  • 不平安但幂等
  • 删除资源
      POST 和 PUT 在创立资源的区别在于,所创立的资源的名称(URI) 是否由客户端决定。例如为我的博文减少一个 java 的分类,生成的门路就是分类名 /categories/java,那么就能够采纳 PUT 办法。不过很多人间接把 POST、GET、PUT、DELETE 间接对应上 CRUD,例如在一个典型的 rails 实现的 RESTful 利用中就是这么做的。

    1.3. HTTP status codes

      状态码批示 HTTP 申请的后果:

  • 1XX:信息
  • 2XX:胜利
  • 3XX:转发
  • 4XX:客户端谬误
  • 5XX:服务端谬误

    1.4. 媒体类型

      HTTP 头中的 Accept 和 Content-Type 可用于形容 HTTP 申请中发送或申请的内容。如果客户端申请 JSON 响应,那么能够将 Accept 设为 application/json。相应地,如果发送的内容是 XML,那么能够设置 Content-Type 为 application/xml。

    2. REST API 设计最佳实际

      这里介绍一些设计 REST API 的最佳实际,大家先记住上面这句话:

    URL 是个句子,其中资源是名词、HTTP 办法是动词。

    2.1. 应用名词来示意资源

      上面是一些例子:

  • GET – /users:返回用户列表
  • GET – /users/100:返回一个特定用户
  • POST – /users:创立一个新用户
  • PUT – /users/200:更新一个特定用户
  • DELETE – /users/711:删除一个特定用户
      不要应用动词:
  • /getAllsers
  • /getUserById
  • /createNewUser
  • /updateUser
  • /deleteUser

    2.2 在 HTTP 头中应用适当的序列化格局

      客户端和服务端都须要晓得通信所用的格局,这个格局要在 HTTP 头中指定:

  • Content-Type 定义申请格局
  • Accept 定义一个可承受的响应格局列表

    2.3 Get 办法和查问参数不该当扭转状态

      应用 PUT, POST 和 DELETE 办法来扭转状态,不要应用 GET 办法来扭转状态:

  • GET /users/711?activate
  • GET /users/711/activate

    2.4. 应用子资源示意关联

      如果一个资源与另一个资源关联,应用子资源:

  • GET /cars/711/drivers/ 返回 711 号汽车的驾驶员列表
  • GET /cars/711/drivers/4 返回 711 号汽车的第 4 号驾驶员

    2.5. 应用适当的 HTTP 办法 (动词)

      再回顾一下这句话:

    URL 是个句子,其中资源是名词、HTTP 办法是动词。

  • GET:获取在 URI 资源中指定的表述,响应音讯体蕴含所申请资源的细节。
  • POST:创立一个 URI 指定的新资源,申请音讯体提供新资源的细节。留神,POST 也能够触发一些操作,而不肯定是要创立新资源。
  • PUT:创立或代替指定 URI 的资源。申请音讯体指定要创立或更新的资源。
  • DELETE:移除指定 URI 的资源。

    2.6. HTTP 响应状态码

      当客户端通过 API 向服务端发动一个申请时,客户端该当晓得反馈:是否失败、通过或者申请谬误。HTTP 状态码是一批标准化代码,在不同的场景下有不同的解释。服务器该当总是返回正确的状态码。
      上面是重要的 HTTP 代码分类:

  • 2xx (胜利分类):这些状态码代码申请动作被接管且被服务器胜利解决。

    • 200:Ok 示意 GET、PUT 或 POST 申请的标准状态码。
    • 201:Created(已创立)示意实例已被创立,多用于 POST 办法。
    • 204:No Content(无内容)示意申请已被胜利解决但没有返回任何内容。罕用于 DELETE 办法返回。
  • 3xx (转发分类)

    • 304:Not Modified(无批改)示意客户端曾经缓存此响应,毋庸再次传输雷同内容。
  • 4xx (客户端谬误分类):这些状态码代表客户端提交了一个谬误申请。

    • 400:Bad Request(谬误申请)示意客户端申请没被解决,因为服务端无奈了解客户端申请。
    • 401:Unauthorized(无受权)示意客户端无权拜访资源,该当加上所需的认证信息后再次申请。
    • 403:Forbidden(禁止拜访)示意申请无效且客户端已获受权,但客户端无权拜访该资源。
    • 404:Not Found(没发现)示意所申请的资源当初不可用。
    • 410:Gone(移除)示意所申请的资源已被移除。
  • 5xx (服务端谬误分类)

    • 500:Internal Server Error(外部服务器谬误)示意申请无效,然而服务端产生了异样。
    • 503:Service Unavailable(服务不可用)示意服务器敞开或不可用,通常是指服务器处于保护状态。

    2.7. 名称规约

      你能够遵循任何名称规约,只有放弃跨利用一致性即可。如果申请体和响应体是 JSON 类型,那么请遵循驼峰名称规约。

    2.8. 搜寻、排序、过滤与分页

      下面一些示例都是在一个数据集上的简略查问,对于简单的数据,咱们须要在 GET 办法 API 上加一些参数来解决。上面是一些示例:

  • 排序:这个例子中,客户想获取排序的公司列表,GET /companies 该当在查问时承受多种排序参数。譬如 GET /companies?sort=rank_asc 将以等级升序的形式对公司进行排序。
  • 过滤:要过滤数据集,咱们能够通过查问参数传递不同的选项。比方 GET /companies?category=banking&location=india 将过滤分类为银行且位于印度的公司。
  • 搜寻:在公司列表中搜寻公司名的 API 端点该当是 GET /companies?search=Digital。
  • 分页:当数据集太大时,咱们该当将数据集宰割成小的数据块,这样有利于晋升服务端性能,也不便客户端解决响应。如 GET /companies?page=23 意味着获取公司列表的第 23 页数据。

    2.9. Restful API 版本

      个别应用不带点的简略数字示意版本,数字前加字母 v 代表版本号,如下所示:

  • /blog/api/v1
  • http://api.yourservice.com/v1…

    2.10. 解决 JSON 谬误体

      API 错误处理机制是很重要的,而且要好好布局。极力推荐总是在返回字段中蕴含谬误音讯。一个 JSON 谬误体该当为开发者提供一些有用的信息:谬误音讯、错误代码以及详细描述。上面是一个较好的示例:

    {
      "code": 1234,
      "message": "Something bad happened :(",
      "description": "More details about the error here"
    }

    2.11. 如何创立 Rest API URL

      举荐应用上面格局的 URL:

  • http(s)://{域名(: 端口号)}/{示意 REST API 的值}/{API 版本}/{辨认资源的门路}
  • http(s)://{示意 REST API 的域名(: 端口号)}/{API 版本}/{辨认资源的门路}
      如下所示:
  • http://example.com/api/v1/mem…
  • http://api.example.com/v1/mem…

    3. 开发基于 Spring Boot 的 Restful Web 服务

      Spring Boot 提供了构建企业应用中 RESTful Web 服务的极佳反对。

    3.1. 引入依赖

      要构建 RESTful Web 服务,咱们须要在构建配置文件中加上 Spring Boot Starter Web 依赖。
      对于 Maven 用户,应用以下的代码在 pom.xml 文件中退出依赖:

    <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>    
    </dependency>

      对于 Gradle 用户,应用以下的代码在 build.gradle 文件中退出依赖:

    compile('org.springframework.boot:spring-boot-starter-web')

    3.2. Rest 相干注解

      在持续构建 RESTful web 服务前,倡议你先要相熟上面的注解:

    Rest Controller

      @RestController 注解用于定义 RESTful web 服务。它提供 JSON、XML 和自定义响应。语法如下所示:

    @RestController
    public class ProductServiceController {}

    Request Mapping

      @RequestMapping 注解用于定义申请 URI 以拜访 REST 端点。咱们能够定义 Request 办法来生产 produce 对象。默认的申请办法是 GET:

    @RequestMapping(value = "/products")
    public ResponseEntity<Object> getProducts() {}
    Request Body
     @RequestBody 注解用于定义申请体内容类型。public ResponseEntity<Object> createProduct(@RequestBody Product product) {}

    Path Variable

      @PathVariable 注解被用于定义自定义或动静的申请 URI,Path variable 被放在申请 URI 中的大括号内,如下所示:

    public ResponseEntity<Object> updateProduct(@PathVariable("id") String id) {}

    Request Parameter

      @RequestParam 注解被用于从申请 URL 中读取申请参数。缺省状况下是必须的,也能够为申请参数设置默认值。如下所示:
    public ResponseEntity<Object> getProduct(
    @RequestParam(value = “name”, required = false, defaultValue = “honey”) String name) {
    }

    3.3. 编写 REST API

    GET API

      上面的示例代码定义了 HTTP GET 申请办法。在这个例子里,咱们应用 HashMap 来在存储 Product。留神咱们应用了 POJO 类来存储产品。
      在这里,申请 URI 是 /products,它会从 HashMap 仓储中返回产品列表。上面的控制器类文件蕴含了 GET 办法的 REST 端点:

    package com.tutorialspoint.demo.controller;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.tutorialspoint.demo.model.Product;
    
    @RestController
    public class ProductServiceController {private static Map<String, Product> productRepo = new HashMap<>();
     static {Product honey = new Product();
        honey.setId("1");
        honey.setName("Honey");
        productRepo.put(honey.getId(), honey);
        
        Product almond = new Product();
        almond.setId("2");
        almond.setName("Almond");
        productRepo.put(almond.getId(), almond);
     }
     @RequestMapping(value = "/products")
     public ResponseEntity<Object> getProduct() {return new ResponseEntity<>(productRepo.values(), HttpStatus.OK);
     }
    }

    POST API

      HTTP POST 申请用于创立资源。这个办法蕴含申请体。咱们能够通过发送申请参数和门路变量来定义自定义或动静 URL。
      上面的示例代码定义了 HTTP POST 申请办法。在这个例子中,咱们应用 HashMap 来存储 Product,这里产品是一个 POJO 类。
      这里,申请 URI 是 /products,在产品被存入 HashMap 仓储后,它会返回字符串。

    package com.tutorialspoint.demo.controller;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.tutorialspoint.demo.model.Product;
    
    @RestController
    public class ProductServiceController {private static Map<String, Product> productRepo = new HashMap<>();
     
     @RequestMapping(value = "/products", method = RequestMethod.POST)
     public ResponseEntity<Object> createProduct(@RequestBody Product product) {productRepo.put(product.getId(), product);
        return new ResponseEntity<>("Product is created successfully", HttpStatus.CREATED);
     }
    }

    PUT API

      HTTP PUT 申请用于更新已有的资源。这个办法蕴含申请体。咱们能够通过发送申请参数和门路变量来定义自定义或动静 URL。
      上面的例子展现了如何定义 HTTP PUT 申请办法。在这个例子中,咱们应用 HashMap 更新现存的产品。此处,产品是一个 POJO 类。
      这里,申请 URI 是 /products/{id},在产品被存入 HashMap 仓储后,它会返回字符串。留神咱们应用门路变量 {id} 定义须要更新的产品 ID:

    package com.tutorialspoint.demo.controller;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    import com.tutorialspoint.demo.model.Product;
    
    @RestController
    public class ProductServiceController {private static Map<String, Product> productRepo = new HashMap<>();
     
     @RequestMapping(value = "/products/{id}", method = RequestMethod.PUT)
     public ResponseEntity<Object> updateProduct(@PathVariable("id") String id, @RequestBody Product product) {productRepo.remove(id);
        product.setId(id);
        productRepo.put(id, product);
        return new ResponseEntity<>("Product is updated successsfully", HttpStatus.OK);
     }   
    }

    DELETE API

      HTTP Delete 申请用于删除存在的资源。这个办法不蕴含任何申请体。咱们能够通过发送申请参数和门路变量来定义自定义或动静 URL。
      上面的例子展现如何定义 HTTP DELETE 申请办法。这个例子中,咱们应用 HashMap 来移除现存的产品,用 POJO 来示意。
      申请 URI 是 /products/{id} 在产品被从 HashMap 仓储中删除后,它会返回字符串。咱们应用门路变量 {id} 来定义要被删除的产品 ID。

    package com.tutorialspoint.demo.controller;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.tutorialspoint.demo.model.Product;
    
    @RestController
    public class ProductServiceController {private static Map<String, Product> productRepo = new HashMap<>();
     
     @RequestMapping(value = "/products/{id}", method = RequestMethod.DELETE)
     public ResponseEntity<Object> delete(@PathVariable("id") String id) {productRepo.remove(id);
        return new ResponseEntity<>("Product is deleted successsfully", HttpStatus.OK);
     }
    }

正文完
 0