Java RESTful Web Service实战(第2版) 2.6 内容协商

简介:

2.6 内容协商

一个资源可以有不同格式的表述,表述(即响应实体)的内容是人类可识别的信息,服务器很难使用一种表述来适应所有用户。conneg(HTTP Content Negotiation,内容协商)是指在服务器提供的多种表述中,为特定的请求选择最好的一种表述的处理过程。那么什么是最好,又怎样做到最好呢?服务器和客户端/浏览器之间往复通信来协商用于交换数据的内容格式等信息,达成一致即为最好。内容协商定义在RFC2616的第12节(http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html)。

客户端/浏览器通过使用 HTTP Accept、Accept-Charset、Accept-Language和Accept-Encoding头来定义接收头的信息,将其所期待的格式或MIME类型告知服务器,服务器根据协商算法,返回客户端/浏览器可接受的数据信息。内容协商不只是数据格式协商,还包括语言、编码、字符集等信息。Accept用于数据类型协商;Accept-Language用于语言协商;Accept-Charset用于字符集协商;Accept-Encoding用于压缩算法协商。

JAX-RS2对内容协商的支持,是通过@Produces实现的,其他协商没有从架构上提供支持,可以通过编码从请求头中获取信息并处理。

阅读指南

本节示例源代码地址:https://github.com/feuyeux/jax-rs2-guide-II/tree/master/2.simple-service-3。

相关包:com.example.conneg。

2.6.1 @Produces注解

注解@Produces用于定义方法的响应实体的数据类型,可以定义一个或多个,同时可以为每种类型定义质量因素(qualityfactor)。质量因素是取值范围从0到1的小数值。如果不定义质量因素,那么该类型的质量因素默认为1。我们将结合示例深入了解@Produces注解对媒体类型的影响,示例代码如下。

@Path("conneg-resource")

public class ConnegResource {

  @GET

  @Path("{id}")

  //关注点1:媒体类型为XML

  @Produces(MediaType.APPLICATION_XML)

  public Book getJaxbBook(@PathParam("id") final Long bookId) {

      return new Book(bookId);

  }

 

  @GET

  @Path("{id}")

  //关注点2:媒体类型为JSON

  @Produces(MediaType.APPLICATION_JSON)

  public Book getJsonBook(@PathParam("id") final Long bookId) {

      return new Book(bookId);

  }

}

在这段代码中,getJaxbBook()和getJsonBook()是同等质量因素、资源地址相同的两个GET方法,一个定义响应实体格式为XML,一个定义响应实体格式为JSON,见关注点1和2。那么对同一个资源的访问,JAX-RS2该如何选择处理方法呢?如果请求中明确定义可接受的数据类型为两者之一,处理方法应该是定义相应数据类型的方法。如果两者都定义了,处理方法应该是质量因素高的方法。如果两者都定义,而且数据类型的质量因素是相等的或者没有定义Accept,XML的方法会被优先选择。

客户端明确表述格式为XML,Jersey通过内容协商,会选择getJaxbBook()作为相应的资源方法来处理该请求。其测试代码如下所示。

WebTarget path = target("conneg-resource").path("123");

Builder request = path.request(MediaType.APPLICATION_XML_TYPE);

Book book = request.get(Book.class);

 

1 > GET http://localhost:9998/conneg-resource/123

1 > Accept: application/xml

2 < Content-Type: application/xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><book bookId="123"/>

接下来,测试一个稍微复杂的内容协商。客户端明确表述格式的质量因素JSON高于XML,Jersey会选择资源方法getJsonBook()来处理请求。示例代码如下所示。

WebTarget path = target("conneg-resource").path("123");

Builder request = path.request();

request.header("Accept", "application/xml;q=0.1,application/json;q=0.2");

Book book = request.get(Book.class);

...1 > GET http://localhost:9998/conneg-resource/123 1 > Accept: application/xml;q=0.1,application/json;q=0.2 2 < Content-Type: application/json {"bookId":123}

现在我们清楚了两个同等方法的场景,再来看一个方法中多种数据类型的场景。示例代码如下。

...java

@GET

@Produces({ "application/json; qs=.9", "application/xml; qs=.5" })

@Path("book/{id}")

public Book getBook(@PathParam("id") final Long bookId) {

    return new Book(bookId);

}

在这段代码中,getBook()方法定义了XML和JSON两种表述数据类型,XML的质量因素是0.5(0可以省略),JSON的是0.9。

因此,可以推断,如果客户端请求中,明确接收的数据类型是两者之一,响应实体使用指定类型。如果没有定义或者两者都定义且JSON的质量因素大于或者等于XML,则返回JSON类型。还有一种用例是,两者都定义但JSON的质量因素小于XML,该如何处理请求方法呢?答案是:内容协商的结果按照客户端的喜好选择响应实体的数据类型,即选择XML格式。

其测试代码如下所示,客户端明确表述格式XML优于JSON,虽然服务器端定义的资源方法中JSON的质量因素高,但Jersey会根据客户端的喜好,选择了XML格式作为表述的格式返回。

WebTarget path = target("conneg-resource").path("book").path("123");

Builder request = path.request();

request.header("Accept", "application/xml;q=0.7,application/json;q=0.2");

Book book = request.get(Book.class);

 

1 > GET http://localhost:9998/conneg-resource/book/123

1 > Accept: application/xml;q=0.7,application/json;q=0.2

2 < Content-Type: application/xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><book bookId="123"/>

2.6.2 @Consumes注解

注解@Consumes用于定义方法的请求实体的数据类型,和@Produces不同的是,@Consumes的数据类型的定义只用于JAX-RS2匹配请求处理的方法,不做内容协商使用。如果匹配不到,服务器会返回HTTP状态码415(Unsupported Media Type),示例代码如下。

@POST

//关注点1:@Consumes注解定义了XML和JSON两种格式

@Consumes({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})

@Produces(MediaType.APPLICATION_XML)

public Book getEntity(Book book) {

    LOGGER.debug(book.getBookName());

    return book;

}

final Builder request = target(path).request();

//关注点2

final Book result = request.post(

Entity.entity(book, MediaType.APPLICATION_XML), Book.class);

在这段代码中,getEntity()方法定义了@Consumes媒体类型为XML格式和JSON格式,见关注点1;那么,在客户端请求中,如果请求实体的数据类型定义是两者之一,该方法会被选择为处理请求的方法,否则查找是否有定义为相应数据类型的方法,如果没有抛出javax.ws.rs.NotSupportedException异常,则使用该方法处理请求,见关注点2。

相关文章
|
14天前
|
监控 JavaScript 前端开发
《理解 WebSocket:Java Web 开发的实时通信技术》
【4月更文挑战第4天】WebSocket是Java Web实时通信的关键技术,提供双向持久连接,实现低延迟、高效率的实时交互。适用于聊天应用、在线游戏、数据监控和即时通知。开发涉及服务器端实现、客户端连接及数据协议定义,注意安全、错误处理、性能和兼容性。随着实时应用需求增加,WebSocket在Java Web开发中的地位将更加重要。
|
9天前
|
Java 测试技术
SpringBoot整合单元测试&&关于SpringBoot单元测试找不到Mapper和Service报java.lang.NullPointerException的错误
SpringBoot整合单元测试&&关于SpringBoot单元测试找不到Mapper和Service报java.lang.NullPointerException的错误
15 0
|
2天前
|
Web App开发 Java 应用服务中间件
【Java Web】在 IDEA 中部署 Tomcat
【Java Web】在 IDEA 中部署 Tomcat
8 0
|
3天前
|
安全 Java API
RESTful API设计与实现:Java后台开发指南
【4月更文挑战第15天】本文介绍了如何使用Java开发RESTful API,重点是Spring Boot框架和Spring MVC。遵循无状态、统一接口、资源标识和JSON数据格式的设计原则,通过创建控制器处理HTTP请求,如示例中的用户管理操作。此外,文章还提及数据绑定、验证、异常处理和跨域支持。最后,提出了版本控制、安全性、文档测试以及限流和缓存的最佳实践,以确保API的稳定、安全和高效。
|
15天前
|
XML JSON JavaScript
使用JSON和XML:数据交换格式在Java Web开发中的应用
【4月更文挑战第3天】本文比较了JSON和XML在Java Web开发中的应用。JSON是一种轻量级、易读的数据交换格式,适合快速解析和节省空间,常用于API和Web服务。XML则提供更强的灵活性和数据描述能力,适合复杂数据结构。Java有Jackson和Gson等库处理JSON,JAXB和DOM/SAX处理XML。选择格式需根据应用场景和需求。
|
15天前
|
前端开发 Java API
构建RESTful API:Java中的RESTful服务开发
【4月更文挑战第3天】本文介绍了在Java环境中构建RESTful API的重要性及方法。遵循REST原则,利用HTTP方法处理资源,实现CRUD操作。在Java中,常用框架如Spring MVC简化了RESTful服务开发,包括定义资源、设计表示层、实现CRUD、考虑安全性、文档和测试。通过Spring MVC示例展示了创建RESTful服务的步骤,强调了其在现代Web服务开发中的关键角色,有助于提升互操作性和用户体验。
构建RESTful API:Java中的RESTful服务开发
|
15天前
|
前端开发 安全 Java
使用Java Web框架:Spring MVC的全面指南
【4月更文挑战第3天】Spring MVC是Spring框架的一部分,用于构建高效、模块化的Web应用。它基于MVC模式,支持多种视图技术。核心概念包括DispatcherServlet(前端控制器)、HandlerMapping(请求映射)、Controller(处理请求)、ViewResolver(视图解析)和ModelAndView(模型和视图容器)。开发流程涉及配置DispatcherServlet、定义Controller、创建View、处理数据、绑定模型和异常处理。
使用Java Web框架:Spring MVC的全面指南
|
17天前
|
Java
销售业务管理系统【Web系统】(Java课设)
销售业务管理系统【Web系统】(Java课设)
13 5
|
26天前
|
Java Maven
Maven【2】( Web 工程依赖 Java 工程)(命令行操作)
Maven【2】( Web 工程依赖 Java 工程)(命令行操作)
20 0
|
28天前
|
Java 计算机视觉
java实现人脸识别源码【含测试效果图】——Service层(IUserService)
java实现人脸识别源码【含测试效果图】——Service层(IUserService)
13 1