更新
更多挖掘表明抛出的异常被删除,实际问题是在AsyncResponse的线程中无法解析注入的UriInfo
!
在@Context UriInfo uriInfo;
期间访问AsyncResponse.resume()
会发出以下LoggableFailure
条消息:
无法找到类型为的上下文数据:javax.ws.rs.core.UriInfo
ORIGINAL
根据RFC 7231 HTTP/1.1 Semantics and Control,POST
应该返回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 如果您需要更多信息,请发表评论!
修改
只要我更改了任何链接或标题,请求就会挂起。
答案 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();
}