61.6. 实体 Reader Interceptor


概述

本节介绍如何实施和注册 实体 reader 拦截器,它可让您在客户端侧或服务器端读取消息正文时截获输入流。这通常适用于请求正文的通用转换,如加密和解密,或者压缩和解压缩。

ReaderInterceptor 接口

javax.ws.rs.ext.ReaderInterceptor 接口定义如下:

// Java
...
package javax.ws.rs.ext;

public interface ReaderInterceptor {
    public Object aroundReadFrom(ReaderInterceptorContext context)
            throws java.io.IOException, javax.ws.rs.WebApplicationException;
}

通过实施 ReaderInterceptor 接口,您可以截获消息正文(实体 对象)在服务器端或客户端一侧读取。您可以在以下任意上下文中使用实体读取器拦截:

  • 服务器端- 如果作为服务器端拦截器绑定,则实体读取器在应用程序代码访问时截获请求消息正文(在匹配的资源中)。根据 REST 请求的语义,消息正文可能无法被匹配资源访问,在这种情况下,读取拦截器没有调用。
  • 客户端侧-if 绑定到客户端侧拦截器,则实体读取器在客户端代码访问时截获响应消息正文。如果客户端代码没有明确访问响应消息(例如,通过调用 Response.getEntity 方法),则不会调用 reader 拦截器。

ReaderInterceptorContext 接口

ReaderInterceptoraroundReadFrom 方法接收一个参数 javax.ws.rs.ext.ReaderInterceptorContext,它可用于访问消息正文(实体 对象)和元数据。

ReaderInterceptorContext 接口定义如下:

// Java
...
package javax.ws.rs.ext;

import java.io.IOException;
import java.io.InputStream;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MultivaluedMap;

public interface ReaderInterceptorContext extends InterceptorContext {

    public Object proceed() throws IOException, WebApplicationException;

    public InputStream getInputStream();

    public void setInputStream(InputStream is);

    public MultivaluedMap<String, String> getHeaders();
}

InterceptorContext 接口

ReaderInterceptorContext 接口还支持从基础 InterceptorContext 接口继承的方法。

InterceptorContext 接口定义如下:

// Java
...
package javax.ws.rs.ext;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Collection;

import javax.ws.rs.core.MediaType;

public interface InterceptorContext {

    public Object getProperty(String name);

    public Collection<String> getPropertyNames();

    public void setProperty(String name, Object object);

    public void removeProperty(String name);

    public Annotation[] getAnnotations();

    public void setAnnotations(Annotation[] annotations);

    Class<?> getType();

    public void setType(Class<?> type);

    Type getGenericType();

    public void setGenericType(Type genericType);

    public MediaType getMediaType();

    public void setMediaType(MediaType mediaType);
}

客户端中的实现示例

若要为客户端实施实体读取器拦截器,请定义一个实施 ReaderInterceptor 接口的类。

例如,以下代码显示了客户端侧的实体读取拦截器示例(优先级为 10),它将红帽在传入响应消息正文中替代 COMPANY_NAME 的所有实例:

// Java
package org.jboss.fuse.example;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.annotation.Priority;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.ReaderInterceptorContext;

@Priority(value = 10)
public class SampleClientReaderInterceptor implements ReaderInterceptor {

  @Override
  public Object aroundReadFrom(ReaderInterceptorContext interceptorContext)
          throws IOException, WebApplicationException
  {
    InputStream inputStream = interceptorContext.getInputStream();
    byte[] bytes = new byte[inputStream.available()];
    inputStream.read(bytes);
    String responseContent = new String(bytes);
    responseContent = responseContent.replaceAll("COMPANY_NAME", "Red Hat");
    interceptorContext.setInputStream(new ByteArrayInputStream(responseContent.getBytes()));

    return interceptorContext.proceed();
  }
}

服务器端的实现示例

若要为服务器端实施实体读取器拦截器,请定义一个实施 ReaderInterceptor 接口的类,并通过 @Provider 注释对其进行标注。

例如,以下代码显示了服务器端的实体读取拦截器示例(优先级为 10),它将红帽在传入请求的消息正文中替代 COMPANY_NAME 的所有实例:

// Java
package org.jboss.fuse.example;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.annotation.Priority;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.ReaderInterceptorContext;

@Priority(value = 10)
@Provider
public class SampleServerReaderInterceptor implements ReaderInterceptor {

  @Override
  public Object aroundReadFrom(ReaderInterceptorContext interceptorContext)
          throws IOException, WebApplicationException {
    InputStream inputStream = interceptorContext.getInputStream();
    byte[] bytes = new byte[inputStream.available()];
    inputStream.read(bytes);
    String requestContent = new String(bytes);
    requestContent = requestContent.replaceAll("COMPANY_NAME", "Red Hat");
    interceptorContext.setInputStream(new ByteArrayInputStream(requestContent.getBytes()));

    return interceptorContext.proceed();
  }
}

在客户端绑定 reader 拦截器

使用 JAX-RS 2.0 客户端 API,您可以在 javax.ws.rs.client. Client 对象或 javax.ws.rs.client.client.client .client.client 对象上直接注册实体读取器拦截器。这意味着读者拦截器可以选择性地应用到不同的范围,以便只有某些 URI 路径受到拦截器的影响。

例如,以下代码演示了如何注册 SampleClientReaderInterceptor 拦截器,使其应用于使用 client 对象进行的所有调用:

// Java
...
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
...
Client client = ClientBuilder.newClient();
client.register(SampleClientReaderInterceptor.class);

有关使用 JAX-RS 2.0 客户端注册拦截器的详情,请参考 第 49.5 节 “配置客户端端点”

在服务器端绑定 reader 拦截器

要在服务器端 绑定 读取器拦截器(即,将其安装到 Apache CXF 运行时),请执行以下步骤:

  1. @Provider 注释添加到 reader 拦截器类,如以下代码片段所示:

    // Java
    package org.jboss.fuse.example;
    ...
    import javax.annotation.Priority;
    import javax.ws.rs.WebApplicationException;
    import javax.ws.rs.ext.Provider;
    import javax.ws.rs.ext.ReaderInterceptor;
    import javax.ws.rs.ext.ReaderInterceptorContext;
    
    @Priority(value = 10)
    @Provider
    public class SampleServerReaderInterceptor implements ReaderInterceptor {
      ...
    }

    当 reader 拦截器实现加载到 Apache CXF 运行时,REST 实施会自动扫描载入的类,以搜索标有 @Provider 注解的类( 扫描阶段)。

  2. 在 XML 中定义 JAX-RS 服务器端点(例如,查看 第 18.1 节 “配置 JAX-RS 服务器端点”)时,将 reader 拦截器添加到 jaxrs:providers 元素中的提供程序列表中。

    <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"
        xmlns:cxf="http://cxf.apache.org/blueprint/core"
        ...
    >
        ...
        <jaxrs:server id="customerService" address="/customers">
          ...
          <jaxrs:providers>
            <ref bean="interceptorProvider" />
          </jaxrs:providers>
          <bean id="interceptorProvider" class="org.jboss.fuse.example.SampleServerReaderInterceptor"/>
    
        </jaxrs:server>
    
    </blueprint>
    注意

    此步骤是 Apache CXF 非标准要求。严格根据 JAX-RS 标准进行说明,@Provider 注释应当是绑定拦截器所需的所有内容。但是,在实践中,标准方法非常不灵活,如果大型项目中纳入了许多库,则可能会导致供应商冲突。

Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.