【问题标题】:Jersey - Custom exception mapper not invoked on invalid POST requestJersey - 无效 POST 请求未调用自定义异常映射器
【发布时间】:2019-09-02 16:28:03
【问题描述】:

我正在使用 Jersey 2.22.1 来实现 REST API。

我创建了一个自定义异常映射器来将 RuntimeException 映射到我选择的特定 HTTP 响应代码。

@Provider
public class MyExceptionMapper implements ExceptionMapper<RuntimeException>
{
    @Override
    public Response toResponse(RuntimeException exception)
    {
        ....
    }
}

我的资源类被配置为接受 POST 请求的多个参数。

@Path("rest/api/1.0/test")
public class MyResource
{
    @NotNull(message = "Missing parameter 'param1'")
    @FormParam("param1")
    private String m_param1;

    @NotNull(message = "Missing parameter 'param2'")
    @FormParam("param2")
    private String m_param2;

    @POST
    @Produces(MediaType.TEXT_PLAIN)
    @Consumes("application/x-www-form-urlencoded")
    public Response test(String body)
    {
        ...
    }
}

当我发送不带任何参数的 POST 请求时:

curl -X POST http://192.168.0.2:9989/myApp/rest/api/1.0/test

我希望调用我的自定义异常映射器,但事实并非如此。相反,我得到了一堆IllegalStateException

WARNING: The following warnings have been detected: WARNING: Unknown HK2 failure detected:
MultiException stack 1 of 6
java.lang.IllegalStateException: The @FormParam is utilized when the content type of the request entity is not application/x-www-form-urlencoded
    at org.glassfish.jersey.server.internal.inject.FormParamValueFactoryProvider$FormParamValueFactory.ensureValidRequest(FormParamValueFactoryProvider.java:183)
    at org.glassfish.jersey.server.internal.inject.FormParamValueFactoryProvider$FormParamValueFactory.getForm(FormParamValueFactoryProvider.java:167)
    at org.glassfish.jersey.server.internal.inject.FormParamValueFactoryProvider$FormParamValueFactory.provide(FormParamValueFactoryProvider.java:118)
    at org.glassfish.jersey.server.internal.inject.ParamInjectionResolver.resolve(ParamInjectionResolver.java:134)
    at org.jvnet.hk2.internal.ClazzCreator.resolve(ClazzCreator.java:211)
    at org.jvnet.hk2.internal.ClazzCreator.resolveAllDependencies(ClazzCreator.java:234)
    at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:357)
    at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:471)
    at org.glassfish.jersey.process.internal.RequestScope.findOrCreate(RequestScope.java:162)
    at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2072)
    at org.jvnet.hk2.internal.ServiceLocatorImpl.internalGetService(ServiceLocatorImpl.java:767)
    at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:706)
    at org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:172)
    at org.glassfish.jersey.server.model.MethodHandler$ClassBasedMethodHandler.getInstance(MethodHandler.java:284)
    at org.glassfish.jersey.server.internal.routing.PushMethodHandlerRouter.apply(PushMethodHandlerRouter.java:74)
    at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:109)
    at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:112)
    at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:112)
    at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:112)
    at org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:92)
    at org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:61)
    at org.glassfish.jersey.process.internal.Stages.process(Stages.java:197)
    at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:318)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
    at org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpContainer.service(GrizzlyHttpContainer.java:384)
    at org.glassfish.grizzly.http.server.HttpHandler$1.run(HttpHandler.java:224)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:591)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:571)
    at java.lang.Thread.run(Thread.java:745)

谁能解释为什么我的自定义异常映射器没有被调用?

请注意,如果我在资源方法中抛出 RuntimeException,然后发送有效的 POST 请求,则会调用异常映射器。所以我知道在某种程度上是否有效。

更新

我发现如果我在 HTTP 请求中添加以下内容:

-H "Content-Type: application/x-www-form-urlencoded"

然后我的ConstraintViolationExceptionMapper 被调用。

@Provider
public class ConstraintViolationExceptionMapper implements ExceptionMapper<ConstraintViolationException>
{
    ...
}

但如果我删除ConstraintViolationExceptionMapper,我的自定义异常映射器仍然不会被调用。

【问题讨论】:

  • 因为Jersey提供了一个ViolationException(它是ConstraintViolationException的超类)的映射器来处理违反约束的问题。每个请求只能调用一个映射器,以防止无限循环
  • 你的意思是ValidationException而不是ViolationException吗?
  • 可能,我并没有真正检查过
  • 即使我为ValidationException 提供映射器,当我发送没有标头的请求时也不会调用它。你知道这是为什么吗?
  • 我会将其作为答案的一部分发布。

标签: java jersey jax-rs jersey-2.0


【解决方案1】:

更新前错误

遵循 JAX-RS 规范,对于 @FormParam 和其他 @XxxParams,当在解析参数期间发生异常时,Jersey 会抛出已经映射的异常。这是为了返回正确的响应状态遵循规范。所以我们永远没有机会处理它。

更新问题

Jersey 已经有一个mapper for ValidationException,它是ConstraintViolationException 的超类。因此,当您为ConstrainViolationException 提供映射器时,它比ValidationException 的映射器更具体,因此会被调用。

即使我为ValidationException 提供映射器,当我发送没有标头的请求时也不会调用它。你知道这是为什么吗?

因为参数解析发生在验证之前。

【讨论】:

    【解决方案2】:

    接受的答案似乎不正确(不再正确)。

    所以我们永远没有机会处理它。

    现在不是这样。检查https://stackoverflow.com/a/45478604/1271372中的什么似乎是正确的解决方案

    我遵循了这一点,在 JacksonFeature 之前实现了 ExceptionMapper&lt;SomeParseException&gt; 并在资源配置 register(ExceptionMapperImplementation.class, 1) 中注册了它,它就像一个魅力。注意优先级 1。

    当然,这应该返回代码 400。我必须将响应正文自定义为 JSON,而不是纯文本。

    【讨论】:

      猜你喜欢
      • 2016-06-10
      • 2011-07-18
      • 1970-01-01
      • 1970-01-01
      • 2015-01-01
      • 2015-03-14
      • 2017-06-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多