恐怕在不改变泽西岛本身的情况下,使用当前版本以一种很好的方式实现你想要完成的事情实际上是不可能的。
无论如何,我也不确定根据规范规范使用@Provider 请求特定过滤器是否是正确的方法。但我是谁,我实际上是自己做的。当然也可以在ResourceConfig 中注册过滤器。
一般来说,我建议看一下@NameBinding,但对于这种情况,名称绑定 Jersey-style 是不够的。使用 @NameBinding,您不必自己检查注释,因为 Jersey 已经为您完成了。
不幸的是,再次使用@NameBinding,它是针对这种情况引入的,存在“自动生成”选项处理程序的问题。我做了相当多的挖掘(一些最相关的类/方法是OptionsMethodProcessor、WadlModelProcessor、ResourceModelConfigurator#init 和ServerRuntime ApplicationHandler#initialize),但没有找到充分融入该过程的方法。以下是处理 CORS 的内容:
@NameBinding
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface CrossOrigin {
}
@CrossOrigin
public class CrossOriginResponseFilter implements ContainerResponseFilter {
public void filter(ContainerRequestContext requestContext,
ContainerResponseContext responseContext)
throws IOException {
// do Cross Origin stuff
}
}
@Path("ress")
public class MyResource {
@CrossOrigin
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response save(DetailsDTO details) {
// do something with the details
}
}
但是,虽然这适用于对资源的任何直接请求,但这也不适用于 CORS-preflight-requests,因为 Jersey 不会将 name-binding-annotation @CrossOrigin 应用于预定义/自动生成的 OPTIONS-处理程序。
您可以看到,在请求上下文中查看资源的运行时表示时(不要让所有文本激怒您,重要的是每个 nameBindings-properties 在每个 ResourceMethod 的末尾):
[ResourceMethod{
httpMethod=POST, consumedTypes=[application/json],
producedTypes=[application/json], suspended=false, suspendTimeout=0,
suspendTimeoutUnit=MILLISECONDS, invocable=Invocable{handler=ClassBasedMethodHandler{handlerClass=class de.example.MyResource,
handlerConstructors=[org.glassfish.jersey.server.model.HandlerConstructor@2c253414]}, definitionMethod=public javax.ws.rs.core.Response de.example.MyResource.save(de.example.DetailsDTO),
parameters=[Parameter [type=class de.example.DetailsDTO, source=null, defaultValue=null]],
responseType=class javax.ws.rs.core.Response},
nameBindings=[interface de.example.CrossOrigin]},
ResourceMethod{
httpMethod=OPTIONS, consumedTypes=[*/*],
producedTypes=[application/vnd.sun.wadl+xml], suspended=false,
suspendTimeout=0, suspendTimeoutUnit=MILLISECONDS,
invocable=Invocable{handler=ClassBasedMethodHandler{handlerClass=class org.glassfish.jersey.server.wadl.processor.WadlModelProcessor$OptionsHandler,
handlerConstructors=[org.glassfish.jersey.server.model.HandlerConstructor@949030f]},
definitionMethod=public abstract java.lang.Object org.glassfish.jersey.process.Inflector.apply(java.lang.Object),
parameters=[Parameter [type=interface javax.ws.rs.container.ContainerRequestContext, source=null, defaultValue=null]], responseType=class javax.ws.rs.core.Response},
nameBindings=[]},
ResourceMethod{
httpMethod=OPTIONS, consumedTypes=[*/*], producedTypes=[text/plain],
suspended=false, suspendTimeout=0, suspendTimeoutUnit=MILLISECONDS,
invocable=Invocable{handler=ClassBasedMethodHandler{handlerClass=class org.glassfish.jersey.server.wadl.processor.OptionsMethodProcessor$PlainTextOptionsInflector,
handlerConstructors=[]}, definitionMethod=public abstract java.lang.Object org.glassfish.jersey.process.Inflector.apply(java.lang.Object),
parameters=[Parameter [type=interface javax.ws.rs.container.ContainerRequestContext, source=null, defaultValue=null]],
responseType=class javax.ws.rs.core.Response}, nameBindings=[]},
ResourceMethod{
httpMethod=OPTIONS, consumedTypes=[*/*], producedTypes=[*/*],
suspended=false, suspendTimeout=0, suspendTimeoutUnit=MILLISECONDS,
invocable=Invocable{handler=ClassBasedMethodHandler{handlerClass=class org.glassfish.jersey.server.wadl.processor.OptionsMethodProcessor$GenericOptionsInflector,
handlerConstructors=[]}, definitionMethod=public abstract java.lang.Object org.glassfish.jersey.process.Inflector.apply(java.lang.Object),
parameters=[Parameter [type=interface javax.ws.rs.container.ContainerRequestContext, source=null, defaultValue=null]], responseType=class javax.ws.rs.core.Response},
nameBindings=[]}]
但现在您可以使用名称绑定信息通过创建另一个过滤器自己处理预检请求:
@Provider
@Priority(1)
public class CrossOriginResponseFilter implements ContainerRequestFilter {
Resource res = ((ContainerRequest)requestContext)
.getUriInfo().getMatchedResourceMethod().getParent();
if (res.getResourceMethods().get(0).getNameBindings().contains(CrossOrigin.class)) {
// handlePreflightRequest and abort: requestContext.abortWith(builder.build());
}
}
有趣的是,提取的 Resource res 将仅包含与实际请求 URI 和方法匹配的相关资源方法以及自动生成的 OPTIONS 处理程序,正如您在上面资源的运行时表示中看到的那样方法。示例资源实际上还有更多的方法,POST 和 GET。因此,您可以在此处使用.get(0) 访问所需的信息。
但当心!我没有检查这是否是真的,或者只是当你用单独的路径注释你的资源方法时。所以也许比我这里的简单版本有更多的匹配工作要做。
我自己发现该解决方案非常丑陋,最终得到的过滤器不是特定于方法的,而是简单地处理对任何资源的所有请求(类似于家伙here 的解决方案)。但这应该是对如何“在处理 OPTIONS 请求时找出实际的 (GET/POST) 资源方法”的问题的答案。