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。
使用jMeter对基于SAP ID service进行Authentication的Restful API进行并发测试 这篇文章本来Jerry只在SAP社区上写了英文版的,后来有两位做Marketing Cloud开发的德国同事,写邮件询问关于文章的更多细节,声称这种方式对他们自己的API性能测试很有用,所以我觉得还是值得用中文再写一遍。
《Java RESTful Web Service实战》第一章的实现补漏 韩陆,你好你的书,麻烦写的清楚一点,多写一些,也许还能多点稿费。小韩,写书认真一点。第13页上来就用maven命令行创建项目,这就有问题啊,没有pom.xml文件mvn这个命令怎么跑的起来呢?所以正确的过程是这样的:eclipse上创建项目创建的结果是这样的:
在搭建之前,首先了解一下什么是RESTful,RESTful(Representational state transfer),它并不是一项新技术,而是一种接口规范。
如何使用 JMeter 调用你的 Restful Web Service?进行简单的压力测试和自动化测试 如何使用 JMeter 调用你的 Restful Web Service?进行简单的压力测试和自动化测试 表述性状态传输(REST)作为对基于 SOAP 和 Web 服务描述语言(WSDL)的 Web 服务的简单替代,在 Web 开发上得到了广泛的接受。
相关文章
- JAVA UUID 生成唯一标识
- JAVA学习(四):Java流程控制语句(顺序结构、if条件语句、switch条件语句、循环语句与跳转语句)
- JAVA学习(一):Java介绍及其平台、开发环境的配置与搭建
- Java实现插入排序
- Java实现 蓝桥杯VIP 算法训练 麦森数
- Java通过mysql-connector-java-8.0.11连接MySQL Server 8.0遇到的几个问题
- Eclipse 报 “Exception in thread "main" java.lang.OutOfMemoryError: Java heap space ”错误的解决办法
- Java 实现大整数加减乘除
- java 11 标准Java异步HTTP客户端
- 【JAVA】Java 异常中e的getMessage()和toString()方法的异同
- k8s java客户端client-java pom地址
- Interview:Java岗位面试—面试求职攻略之一个JAVA程序员面试心得(非常值得收藏)
- 【java】Java 枚举(enum)如何使用以及原理
- Java main方法_解释Java中的main方法,及其作用_一个java文件中可包含多个main方法
- 【Java用法】java 8两个List集合取交集、并集、差集、去重并集
- 解决idea出现的java.lang.OutOfMemoryError: Java heap space的问题
- Java通过PDF模板导出数据 adobe acrobat的PDF编辑器 itextpdf java导出文件输出流
- Java如何获取IP属地 ip2region failed to create searcher with x:java.io.FileNotFoundException:( 系统找不到指定的路径)
- 【Java基金会】Java整理面试问题和评论(一)
- JAVA运行程序代码段
- Java开发技术之成为高级java工程师必须学习的三个技术