gpt4 book ai didi

java - 带有 Jersey 的 OPTIONS 请求的 CORS header

转载 作者:搜寻专家 更新时间:2023-10-31 20:32:42 26 4
gpt4 key购买 nike

我有一个 REST API,我希望其中的一些 方法具有特定的 CORS header 。我在资源方法上有一个注解,还有一个过滤器来添加标题:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface CorsHeaders {}

@Path("api")
class MyApi {
@CorsHeaders
@GET
public Response m() {
return Response.ok().build();
}
}

@Provider
class CorsFilter implements ContainerResponseFilter {
@Context private ResourceInfo resourceInfo;

@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
if (resourceInfo.getResourceMethod().getAnnotation(CorsHeaders.class) != null) {
responseContext.getHeaders().add(/* appropriate headers here*/);
}
}
}

这适用于所有 GET、POST 等请求。它不适用于 OPTIONS 请求,因为资源方法将解析为 org.glassfish.jersey.server.wadl.processor.WadlModelProcessor$OptionsHandler 而不是我的方法,因此注释将不存在.

我可以通过添加一个 @OPTIONS @CorsHeaders public Response options() { return Response.ok().build(); 来解决这个问题} 方法添加到我的 API 类(在相同的 @Path 上),但我不想对所有方法都这样做。

在处理 OPTIONS 请求时如何找到实际的 (GET/POST) 资源方法?

最佳答案

恐怕在不更改 Jersey 本身的情况下使用当前版本实际上不可能以一种很好的方式实现您想要完成的目标。

无论如何,根据规范规范,我也不太确定使用 @Provider 请求特定过滤器是否是正确的方法。但我是谁说的 我实际上是自己做的。当然也可以在 ResourceConfig 中注册过滤器。一般来说,我建议看一下 @NameBinding ,但对于这种情况,名称绑定(bind) Jersey-style 是不够的。使用 @NameBinding,您不必自己检查注释,因为 Jersey 已经为您完成了。

不幸的是再次使用 @NameBinding,它是为这种情况引入的,存在“自动生成”选项处理程序的问题。我做了很多挖掘(一些最相关的类/方法是 OptionsMethodProcessorWadlModelProcessorResourceModelConfigurator#initServerRuntime ApplicationHandler# initialize) 但没有找到一种方法来充分 Hook 到进程中。以下是足以处理 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 不将名称绑定(bind)注释 @CrossOrigin 应用于预定义/自动生成的选项处理程序。您可以看到,在请求上下文中查看资源的运行时表示时(不要让所有文本激怒您,重要的是每个 nameBindings 末尾的属性 资源方法):

[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=[]}]

但是现在您可以通过创建另一个过滤器使用名称绑定(bind)信息来自己处理预检请求:

@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());
}
}

有趣的是,提取的资源 res 将仅包含与实际请求 URI 和方法匹配的相关资源方法以及自动生成的 OPTIONS-handlers,如您在上面的运行中所见-资源方法的时间表示。示例资源实际上有更多方法、POST 和 GET。因此,您可以在此处使用 .get(0) 访问所需的信息。

但请注意! 我没有检查这是否在任何情况下都是正确的,或者只是当您例如用单独的路径注释您的资源方法时。因此,与我这里的简单版本相比,可能需要做更多的匹配工作。

我自己发现该解决方案非常丑陋,最终得到的过滤器不是特定于方法的,而是简单地处理对任何资源的所有请求(类似于 here 的解决方案)。但它应该是对如何“在处理 OPTIONS 请求时找出实际的 (GET/POST) 资源方法”这个问题的答案。

关于java - 带有 Jersey 的 OPTIONS 请求的 CORS header ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38009678/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com