2.12. RESTEasy Filters 和 Interceptors
Jakarta RESTful Web Services 有两个不同的拦截器概念:过滤器和拦截器。过滤器主要用于修改或处理传入和传出请求标头或响应标头。它们在请求和响应处理之前和之后执行。
2.12.1. 服务器端过滤器 复制链接链接已复制到粘贴板!
在服务器端,您有两种不同类型的过滤器:Container RequestFilters 和 ContainerResponseFilters。ContainerRequestFilters 在调用 Jakarta RESTful Web Services 资源方法之前运行。ContainerResponseFilters 在调用 Jakarta RESTful Web Services 资源方法后运行。
此外,有两种类型的 ContainerRequestFilters :预匹配和后匹配。预匹配 ContainerRequestFilters 由 @PreMatching 注释指定,并在 Jakarta RESTful Web Services 资源方法与传入 HTTP 请求匹配之前执行。匹配后 ContainerRequestFilters 由 @PostMatching 注释指定,并在 Jakarta RESTful Web Services 资源方法与传入 HTTP 请求匹配后执行。
预匹配过滤器通常用于修改请求属性,以更改它与特定资源方法的匹配方式,如 strip .xml 并添加 Accept 标头。ContainerRequestFilters 可以通过调用 ContainerRequestContext.abortWith(Response) 来中止请求。例如,如果过滤器实施了自定义身份验证协议,它可能希望中止。
执行资源类方法后,Jakarta RESTful Web Services 运行所有 ContainerResponseFilters。通过这些过滤器,您可以在清理并发送到客户端之前修改传出响应。
示例:请求过滤器
示例:Response Filter
2.12.2. 客户端过滤器 复制链接链接已复制到粘贴板!
有关客户端过滤器的更多信息,请参阅本指南的 Jakarta RESTful Web Services Client API 部分。
2.12.3. RESTEasy Interceptors 复制链接链接已复制到粘贴板!
2.12.3.1. 拦截 Jakarta RESTful Web Services Invocations 复制链接链接已复制到粘贴板!
RESTEasy 可以拦截 Jakarta RESTful Web Services 调用,并通过类似于侦听器的对象进行路由。
虽然过滤器修改请求或响应标头,而拦截器会处理消息正文。拦截器在与其对应的读取器或写入器相同的调用堆栈中执行。ReaderInterceptors 围绕执行 MessageBodyReaders 打包.WriterInterceptors 围绕执行 MessageBodyWriters 打包。它们可用于实施特定的内容编码。它们可用于生成数字签名,或者在托管之前或之后发布或预处理 Java 对象模型。
ReaderInterceptors 和 WriterInterceptors 可用于服务器或客户端。它们标有 @Provider,以及 @ServerInterceptor 或 @ClientInterceptor,以便 RESTEasy 知道是否将它们添加到拦截器列表中。
这些拦截器围绕调用 MessageBodyReader.readFrom()或 MessageBodyWriter.writeTo()进行 打包。它们可用于嵌套 输出 或 输入 流。
示例:Interceptor
拦截器和 MessageBodyReader 或 Writer 在一个大型 Java 调用堆栈中调用。ReaderInterceptorContext.proceed() 或 WriterInterceptorContext.proceed() 被调用来进入下一个拦截器;如果没有要调用的拦截器,则调用拦截 器( ) 或 writeTo() 方法 。此打包允许在对象到达 Reader 或 Writer 之前修改对象,然后在 continue () 返回后进行清理。
以下示例是服务器端拦截器,它为响应添加一个标头值。
2.12.3.2. 注册 Interceptor 复制链接链接已复制到粘贴板!
要在应用中注册 RESTEasy Jakarta RESTful Web Services 拦截器,请将它列在 context-param 元素的 resteasy.providers 参数下的 web.xml 文件中,或者以类或对象形式在 Application. getClasses()或 方法中将它列出。
Application.get Singletons()
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>my.app.CustomInterceptor</paramvalue>
</context-param>
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>my.app.CustomInterceptor</paramvalue>
</context-param>
2.12.4. GZIP 压缩与解压缩 复制链接链接已复制到粘贴板!
RESTEasy 支持 GZIP 压缩和解压缩。为了支持 GZIP 解压缩,客户端框架或 Jakarta RESTful Web Services 服务会自动解压缩具有 gzip Content-Encoding 的消息正文,并且它可以自动将 Accept-Encoding 标头设置为 gzip,因此您不必手动设置此标头。若要支持 GZIP 压缩,如果客户端框架正在发送请求,或者服务器正在发送一个响应( Content-Encoding 标头设为 gzip ),RESTEasy 会压缩传出消息。您可以使用 @org.jboss.resteasy.annotation.GZIP 注释来设置 Content-Encoding 标头。
以下示例标记传出消息正文 进行 gzip 压缩的顺序。
示例:GZIP 压缩
示例:GZIP 压缩服务器响应标签
2.12.4.1. 配置 GZIP 压缩和解压缩 复制链接链接已复制到粘贴板!
RESTEasy 默认禁用 GZIP 压缩和解压缩,以防止对可能较大但已被攻击者压缩并发送到服务器的实体解压缩。
有三个与 GZIP 压缩和解压缩相关的拦截器:
-
org.jboss.resteasy.plugins.interceptors.GZIPDecodingInterceptor:如果Content-Encoding标头存在并且值为gzip,GZIPDecodingInterceptor将安装解压缩邮件正文的输入流。 -
org.jboss.resteasy.plugins.interceptors.GZIPEncodingInterceptor:如果Content-Encoding标头存在并且值为gzip,GZIPEncodingInterceptor会安装压缩邮件正文的输出流。 org.jboss.resteasy.plugins.interceptors.AcceptEncodingGZIPFilter:如果Accept-Encoding标头不存在,AcceptEncodingGZIPFilter会添加值为gzip 的标头。如果Accept-EncodingAccept-Encoding标头存在但不包含gzip,AcceptEncodingGZIPFilter拦截器将附加该值gzip。注意启用 GZIP 压缩或解压缩并不依赖于
AcceptEncodingGZIPFilter拦截器的存在性。
启用 GZIP 解压缩器可以为从压缩消息正文中提取的 GZIPDecodingInterceptor 的字节数设置上限。默认限值为 10,000,000。
2.12.4.2. 服务器端 GZIP 配置 复制链接链接已复制到粘贴板!
您可以通过在类路径上的 javax.ws.rs.ext.Providers 文件中包含它们的类名称来启用拦截器。已定义文件的上限使用 Web 应用上下文参数 resteasy.gzip.max.input 进行设置。如果在服务器端超过这个限制,GZIPDecodingInterceptor 将返回一个带有状态为 413 的响应 - Request Entity Too Large 以及指定上限的消息。
2.12.4.2.1. 客户端 GZIP 配置 复制链接链接已复制到粘贴板!
您可以通过将 GZIP 拦截器注册到 客户端 或 WebTarget 来启用 GZIP 拦截器。例如:
Client client = new ResteasyClientBuilder() // Activate gzip compression on client:
.register(AcceptEncodingGZIPFilter.class)
.register(GZIPDecodingInterceptor.class)
.register(GZIPEncodingInterceptor.class)
.build();
Client client = new ResteasyClientBuilder() // Activate gzip compression on client:
.register(AcceptEncodingGZIPFilter.class)
.register(GZIPDecodingInterceptor.class)
.register(GZIPEncodingInterceptor.class)
.build();
您可以通过创建具有特定值的 GZIPDecodingInterceptor 实例来配置定义文件的上限:
Client client = new ResteasyClientBuilder() // Activate gzip compression on client:
.register(AcceptEncodingGZIPFilter.class)
.register(new GZIPDecodingInterceptor(256))
.register(GZIPEncodingInterceptor.class)
.build();
Client client = new ResteasyClientBuilder() // Activate gzip compression on client:
.register(AcceptEncodingGZIPFilter.class)
.register(new GZIPDecodingInterceptor(256))
.register(GZIPEncodingInterceptor.class)
.build();
如果在客户端上超过了上限,GZIPDecodingInterceptor 将 引发 ProcessingException,并显示指定上限的消息。
2.12.5. 按资源方法过滤器和 Interceptors 复制链接链接已复制到粘贴板!
有时,您希望过滤器或拦截器仅针对特定资源方法运行。您可以通过两种不同的方式进行此操作:
实施 DynamicFeature Interface
DynamicFeature 界面包含回调方法,配置(ResourceInfo resourceInfo, FeatureContext context),后者会针对部署的 Jakarta RESTful Web Services 方法进行调用。ResourceInfo 参数包含有关当前部署的 Jakarta RESTful Web Services 方法的信息。FeatureContext 是 可配置 接口的扩展。您可以使用此参数的 register() 方法绑定您要分配给此方法的过滤器和拦截器。
示例:使用动态功能接口
在上例中,您使用 AnimalTypeFeature 注册的提供程序必须实施其中一个接口。本例注册了必须实现以下接口之一的供应商 AnimalFilter : ContainerRequestFilter、ContainerInterceptor、Reader Interceptor、WriterInterceptor 或 Feature。在这种情况下,AnimalFilter 将应用到所有标有 GET 注解的资源方法。详情请参阅 动态功能文档。
使用 @NameBinding 注解
@NameBinding 的工作方式与 Jakarta Contexts 和 Dependency Injection 拦截器非常相似。您使用 @NameBinding 标注自定义注释,然后将该自定义注释应用到过滤器和资源方法。
示例:使用 @NameBinding
详情请参阅 NameBinding 文档。
2.12.6. 排序 复制链接链接已复制到粘贴板!
通过对过滤器或拦截器类使用 @Priority 注释来完成排序。
2.12.7. 使用过滤器和拦截器处理异常 复制链接链接已复制到粘贴板!
与过滤器或拦截器关联的例外可以在客户端或服务器端发生。在客户端,您必须处理两种类型的异常: javax.ws.rs.client.ProcessingException 和 javax.ws.rs.client.ResponseProcessingException。如果向服务器发送请求之前 出现了错误,则将在客户端引发 javax.ws.rs.client.ProcessingException。如果处理服务器收到的响应时存在错误,则客户端将 引发 javax.ws.rs.client.ResponseProcessingException。
在服务器端,由过滤器或拦截器抛出的异常处理方式与来自 Jakarta RESTful Web Services 方法的其他 异常处理方式相同,该方法尝试查找引发异常 的异常。有关如何在 Jakarta RESTful Web Services 方法中处理异常的更多详细信息,请参见 例外处理 部分。