带有Location标头的JAX-RS AsyncResponse.resume()

时间:2015-07-17 11:40:02

标签: rest java-ee asynchronous jax-rs resteasy

更新

更多挖掘表明抛出的异常被删除,实际问题是在AsyncResponse的线程中无法解析注入的UriInfo

@Context UriInfo uriInfo;期间访问AsyncResponse.resume()会发出以下LoggableFailure条消息:

  

无法找到类型为的上下文数据:javax.ws.rs.core.UriInfo

ORIGINAL

根据RFC 7231 HTTP/1.1 Semantics and ControlPOST应该返回201 CREATED并在标题中提供新资源的位置:

  

原始服务器      应该发送包含Location头的201(Created)响应      为所创建的主资源提供标识符的字段      (第7.1.2节)和描述该状态的表示      请求参考新资源。

在编写同步REST服务器时,javax.ws.rs.core.Response提供了Response.created()简写,就是这样。

我会保存新实体,构建URI并返回

return Response.created(createURL(created)).build();

但是,当我使用

切换到异步方法时

@Suspended javax.ws.rs.container.AsyncResponse

客户端上的HTTP请求将无限挂起:

@POST
public void createUser(@Valid User user, @Suspended AsyncResponse asyncResponse) {
    executorService.submit(() -> {
        User created = userService.create(user);
        asyncResponse.resume(
                Response.created(createURL(created)).build()
        );
    });
}

通过反复试验,我发现修改后的位置标题是负责任的。 如果我返回我的实体并设置201 Created,而不触及标题,请求最终会解决:

@POST
public void createUser(@Valid User user, @Suspended AsyncResponse asyncResponse) {
    executorService.submit(() -> {
        User created = userService.create(user);
        asyncResponse.resume(
                Response.status(Status.CREATED).entity(created).build()  //this works
                //Response.created(createURL(created)).build()
        );
    });
}

那么问题是什么?我误解了这些概念吗?

我在GlassFish4.1上运行RestEasy 如果您需要更多信息,请发表评论!

修改

只要我更改了任何链接或标题,请求就会挂起。

1 个答案:

答案 0 :(得分:4)

万一有人遇到同样的问题:

问题是我使用@Context UriInfo uriInfo通过注入的.getAbsolutePathBuilder()创建了位置标头。

该方法在同步服务器中工作,因为访问UriInfo的线程仍然具有相同的请求上下文。

但是,当我切换到异步方法时,最终必须访问Runnable的基础uriInfo.getAbsolutePathBuilder()不在任何上下文中 - 因此抛出了一个暂停进一步执行的异常。

解决方法:

在任何应该返回位置标头的异步方法中,我.getAbsolutePathBuilder()仍在上下文中。然后可以在异步运行中使用UriBuilder实现:

@POST
public void createUser(@Valid User user, @Suspended AsyncResponse asyncResponse) {
    UriBuilder ub = uriInfo.getAbsolutePathBuilder();

    executorService.submit(() -> {
        User created = userService.create(user);
        asyncResponse.resume(
                Response.created(createURL(ub, created)).build()
        );
    });
}

private URI createURL(UriBuilder builder, ApiRepresentation entity) {
    return builder.path(entity.getId().toString()).build();
}