61.2. 容器请求过滤器


概述

本节介绍如何实施和注册容器请求 过滤器,该过滤器 用于截获 server (容器)端的传入请求消息。容器请求过滤器通常用于处理服务器端的标头,并可用于任何类型的通用请求处理(即处理独立于特定资源方法的处理)。

此外,容器请求过滤器是特殊情况的一部分,因为它可以在两个不同的扩展点上安装: PreMatchContainerRequest (资源匹配步骤前)和 ContainerRequest (资源匹配步骤之后)。

ContainerRequestFilter 接口

javax.ws.rs.container.ContainerRequestFilter 接口定义如下:

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

import java.io.IOException;

public interface ContainerRequestFilter {
    public void filter(ContainerRequestContext requestContext) throws IOException;
}
Copy to clipboard

通过实现 ContainerRequestFilter 接口,您可以在服务器端为以下扩展点创建一个过滤器:

  • PreMatchContainerRequest
  • ContainerRequest

ContainerRequestContext 接口

ContainerRequestFilter 的过滤器 方法接收类型为 javax.ws.rs.container.ContainerRequestContext 的单个参数,它可用于访问传入的请求消息及其关联的元数据。ContainerRequestContext 接口定义如下:

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

import java.io.InputStream;
import java.net.URI;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;


public interface ContainerRequestContext {

    public Object getProperty(String name);

    public Collection getPropertyNames();

    public void setProperty(String name, Object object);

    public void removeProperty(String name);

    public UriInfo getUriInfo();

    public void setRequestUri(URI requestUri);

    public void setRequestUri(URI baseUri, URI requestUri);

    public Request getRequest();

    public String getMethod();

    public void setMethod(String method);

    public MultivaluedMap getHeaders();

    public String getHeaderString(String name);

    public Date getDate();

    public Locale getLanguage();

    public int getLength();

    public MediaType getMediaType();

    public List getAcceptableMediaTypes();

    public List getAcceptableLanguages();

    public Map getCookies();

    public boolean hasEntity();

    public InputStream getEntityStream();

    public void setEntityStream(InputStream input);

    public SecurityContext getSecurityContext();

    public void setSecurityContext(SecurityContext context);

    public void abortWith(Response response);
}
Copy to clipboard

PreMatchContainerRequest 过滤器的实现示例

要为 PreMatchContainerRequest 扩展点(即,在资源匹配之前执行过滤器的位置)实现容器请求过滤器,请定义一个实施 ContainerRequestFilter 接口的类,确保为类添加 @PreMatching 注解(选择 PreMatchContainerRequest 扩展点)。

例如,以下代码显示了在 PreMatchContainerRequest 扩展点中安装的简单容器请求过滤器示例,其优先级为 20:

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

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.PreMatching;
import javax.annotation.Priority;
import javax.ws.rs.ext.Provider;

@PreMatching
@Priority(value = 20)
@Provider
public class SamplePreMatchContainerRequestFilter implements
  ContainerRequestFilter {

  public SamplePreMatchContainerRequestFilter() {
    System.out.println("SamplePreMatchContainerRequestFilter starting up");
  }

  @Override
  public void filter(ContainerRequestContext requestContext) {
    System.out.println("SamplePreMatchContainerRequestFilter.filter() invoked");
  }
}
Copy to clipboard

ContainerRequest 过滤器的实现示例

要为 ContainerRequest 扩展点实施容器请求过滤器(即,过滤器在资源匹配 后执行 的位置),请定义一个实施 ContainerRequestFilter 接口的类,而无需 @PreMatching 注解。

例如,以下代码显示了在 ContainerRequest 扩展点中安装的简单容器请求过滤器示例,其优先级为 30 :

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

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.ext.Provider;
import javax.annotation.Priority;

@Provider
@Priority(value = 30)
public class SampleContainerRequestFilter implements ContainerRequestFilter {

  public SampleContainerRequestFilter() {
    System.out.println("SampleContainerRequestFilter starting up");
  }

  @Override
  public void filter(ContainerRequestContext requestContext) {
    System.out.println("SampleContainerRequestFilter.filter() invoked");
  }
}
Copy to clipboard

注入 ResourceInfo

ContainerRequest 扩展点(即发生资源匹配 ),可以通过注入 ResourceInfo 类来访问匹配的资源类和资源方法。例如,以下代码演示了如何注入 ResourceInfo 类作为 ContainerRequestFilter 类的字段:

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

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.ext.Provider;
import javax.annotation.Priority;
import javax.ws.rs.core.Context;

@Provider
@Priority(value = 30)
public class SampleContainerRequestFilter implements ContainerRequestFilter {

  @Context
  private ResourceInfo resinfo;

  public SampleContainerRequestFilter() {
    ...
  }

  @Override
  public void filter(ContainerRequestContext requestContext) {
    String resourceClass = resinfo.getResourceClass().getName();
    String methodName    = resinfo.getResourceMethod().getName();
    System.out.println("REST invocation bound to resource class: " + resourceClass);
    System.out.println("REST invocation bound to resource method: " + methodName);
  }
}
Copy to clipboard

中止调用

通过创建合适的容器请求过滤器实施,可以中止服务器端调用。通常,这对在服务器端实施安全功能很有用:例如,为了实现身份验证功能或授权功能。如果传入的请求无法成功进行身份验证,您可以在容器请求过滤器内中止调用。

例如,以下预匹配功能尝试从 URI 的查询参数中提取用户名和密码,并调用验证方法来检查用户名和密码凭证。如果身份验证失败,则调用在 ContainerRequestContext 对象上的 abortWith 中止,传递要返回到客户端的错误响应。

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

import javax.annotation.Priority;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.Provider;

@PreMatching
@Priority(value = 20)
@Provider
public class SampleAuthenticationRequestFilter implements
  ContainerRequestFilter {

  public SampleAuthenticationRequestFilter() {
    System.out.println("SampleAuthenticationRequestFilter starting up");
  }

  @Override
  public void filter(ContainerRequestContext requestContext) {
    ResponseBuilder responseBuilder = null;
    Response response = null;

    String userName = requestContext.getUriInfo().getQueryParameters().getFirst("UserName");
    String password = requestContext.getUriInfo().getQueryParameters().getFirst("Password");
    if (authenticate(userName, password) == false) {
      responseBuilder = Response.serverError();
      response = responseBuilder.status(Status.BAD_REQUEST).build();
      requestContext.abortWith(response);
    }
  }

  public boolean authenticate(String userName, String password) {
    // Perform authentication of 'user'
    ...
  }
}
Copy to clipboard

绑定服务器请求过滤器

绑定 服务器请求过滤器(即要将它安装到 Apache CXF 运行时中),请执行以下步骤:

  1. @Provider 注释添加到容器请求过滤器类,如以下代码片段所示:

    // Java
    package org.jboss.fuse.example;
    
    import javax.ws.rs.container.ContainerRequestContext;
    import javax.ws.rs.container.ContainerRequestFilter;
    import javax.ws.rs.ext.Provider;
    import javax.annotation.Priority;
    
    @Provider
    @Priority(value = 30)
    public class SampleContainerRequestFilter implements ContainerRequestFilter {
      ...
    }
    Copy to clipboard

    当容器请求过滤器实施加载到 Apache CXF 运行时中时,REST 实施会自动扫描加载的类,以搜索标有 @Provider 注释( 扫描阶段)。

  2. 在 XML 中定义 JAX-RS 服务器端点(例如,请参阅 第 18.1 节 “配置 JAX-RS 服务器端点”)时,将服务器请求过滤器添加到 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="filterProvider" />
          </jaxrs:providers>
          <bean id="filterProvider" class="org.jboss.fuse.example.SampleContainerRequestFilter"/>
    
        </jaxrs:server>
    
    </blueprint>
    Copy to clipboard
    注意

    此步骤是 Apache CXF 的非标准要求。根据 JAX-RS 标准,严格说,@Provider 注释应当是绑定过滤器所需的所有内容。但是在实践中,标准方法有些不灵活,当许多库包含在大型项目中时,可能会导致禁止提供程序。

返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

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

让开源更具包容性

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

關於紅帽

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

Theme

© 2025 Red Hat, Inc.