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。

时间: 2024-11-23 07:43:03

Java RESTful Web Service实战(第2版) 2.6 内容协商的相关文章

Java RESTful Web Service实战(第2版)

Java核心技术系列 Java RESTful Web Service实战 (第2版) 韩陆 著 图书在版编目(CIP)数据 Java RESTful Web Service实战 / 韩陆著. -2版. -北京:机械工业出版社,2016.7 (Java核心技术系列) ISBN 978-7-111-54213-1 Ⅰ. J-   Ⅱ. 韩-   Ⅲ. JAVA语言-程序设计   Ⅳ. TP312 中国版本图书馆CIP数据核字(2016)第156331号 Java RESTful Web Servi

Java RESTful Web Service实战(第2版) 导读

Java核心技术系列 Java RESTful Web Service实战 (第2版) 韩陆 著   半年前初识韩陆的时候,我们就聊到他正在写的这本书,当得知我从2006年就参与了Apache CXF开发,他立即邀请我为他的新书写序,我也就欣然答应了. Apache CXF作为JAXWS以及JAX-RS规范的实现框架,已经成为很多Web服务开发者必选的开发框架.作为这一框架的开发维护者之一,我的日常工作经常需要熟悉这些JSR规范,并实现JSR所定义的API,解决最终用户的使用问题. 熟悉Java

Java RESTful Web Service实战(第2版) 2.3 传输格式

2.3 传输格式 本节要考虑的就是如何设计表述,即传输过程中数据采用什么样的数据格式.通常,REST接口会以XML和JSON作为主要的传输格式,这两种格式数据的处理是本节的重点.那么Jersey是否还支持其他的数据格式呢?答案是肯定的,让我们逐一掌握各种类型的实现. 2.3.1 基本类型 Java的基本类型又叫原生类型,包括4种整型(byte.short.int.long).2种浮点类型(float.double).Unicode编码的字符(char)和布尔类型(boolean). 阅读指南 本

Java RESTful Web Service实战(第2版) 1.2 解读REST服务

1.2 解读REST服务 RESTful对应的中文是REST式的,RESTful Web Service的准确翻译应该是REST式的Web服务,我们通常简称为REST服务.RESTful的应用或者Web服务是最常见的两种REST式的项目部署.存在的方式.本节将介绍REST服务并对比其与传统Web Services的不同. 1.2.1 REST式的Web服务 RESTful Web Service是一种遵守REST式风格的Web服务.REST服务是一种ROA(Resource-Oriented A

Java RESTful Web Service实战(第2版) 1.3 解读JAX-RS标准

1.3 解读JAX-RS标准 JAX-RS是Java领域的REST式的Web服务的标准规范,是使用Java完成REST服务的基本约定. 1.3.1 JAX-RS2标准 Java领域中的Web Service是指实现SOAP协议的JAX-WS.直到Java EE 6(发布于2008年9月)通过JCP(Java Community Process)组织定义的JSR311(http://www.jcp.org/en/jsr/detail?id=311),才将REST在Java领域标准化. JSR311

Java RESTful Web Service实战(第2版) 1.4 Jersey项目概要

1.4 Jersey项目概要 Jersey是JAX-RS标准的参考实现,是Java领域中最纯正的REST服务开发框架.本节将带读者走近Jersey的世界. Jersey项目是GlashFish项目的一个子项目,专门用来实现JAX-RS(JSR 311 & JSR 339)标准,并提供了扩展特性. 1.4.1 获得Jersey Jersey项目的地址是https://jersey.java.net.该网站同时提供了JAX-RS和JAX-RS2两个并行版本,分别是JAX-RS1.1(截至本书发稿,最

Java RESTful Web Service实战(第2版) 1.5 快速实现Java REST服务

1.5 快速实现Java REST服务 本节包含两个Jersey实战示例,目的是让读者具备快速创建REST服务的能力. 在开始实战之前,首先需要读者确认你的环境是否已经安装了Java和Maven.这里使用Maven命令,示例如下. mvn -v   Apache Maven 3.3.3 (7994120775791599e205a5524ec3e0dfe41d4a06; 2015-04-22T19:57:37+08:00) Maven home: /usr/local/Cellar/maven/

Java RESTful Web Service实战(第2版) 1.7 Java领域的其他REST实现

1.7 Java领域的其他REST实现 Java领域存在很多REST实现,我们以是否遵循JAX-RS标准,将它们分为两组.前者是JAX-RS标准参考实现之外的厂商实现,后者要么是因为出现较JAX-RS标准早,要么干脆跳出了JAX-RS标准的定义,以自身框架一致性为目标,实现了一套独有的对REST开发的支持.本节将概括性地介绍这些实现工具,以便读者有所对比和选择. 1.7.1 JAX-RS的其他实现 JAX-RS标准发布后,诸多厂商推出了自己的基于JAX-RS标准的实现.其中最有影响力的当属来自J

Java RESTful Web Service实战(第2版) 1.9 本章小结

1.9 本章小结 本章主要讲述了REST服务的概念和实战.先后解读了REST.REST服务.JAX-RS2标准中的重要概念,对JAX-RS2的参考实现项目Jersey进行了简单而全面的概述.随后讲述了如何快速创建REST应用和REST服务,介绍了基于JAX-RS2标准的其他项目和其他非JAX-RS2标准的.著名的Java项目. 通过阅读本章,读者可以清楚地掌握Java领域开发REST服务中的基本概念. 本章主要的知识点如下. REST是什么 一种架构风格. HTTP+URI+XML是REST的基

Java RESTful Web Service实战(第2版) 1.6 快速了解Java REST服务

1.6 快速了解Java REST服务 1.6.1 REST工程类型 在REST服务中,资源类是接收REST请求并完成响应的核心类,而资源类是由REST服务的"提供者"来调度的.这一概念类似其他框架中自定义的Servlet类,该类会将请求分派给指定的Controller/Action类来处理.本节将讲述REST中的这个提供者,即JAX-RS2中定义的Application以及Servlet. Application类在JAX-RS2(JSR339,详见参考资料)标准中定义为javax.