更新
更多的挖掘表明,抛出的异常被丢弃,实际的问题是在AsyncResponse的线程中无法解析注入的UriInfo
!
在@Context UriInfo uriInfo;
期间访问AsyncResponse.resume()
会显示以下LoggableFailure
消息:
找不到以下类型的上下文数据:javax.ws.rs.core.UriInfo
原版的
根据RFC 7231 HTTP/1.1 Semantics and Control,POST
应该返回201 CREATED
并在标头中提供新资源的位置:
原始服务器
应该发送包含Location标头的201(已创建)响应
为创建的主要资源提供标识符的字段
(第7.1.2节)和描述状态的表述。
请求,同时引用新资源。
编写同步REST Server时,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
如果您需要更多信息,请发表评论!
编辑
一旦我更改了任何链接或标题,该请求就会挂起。
最佳答案
如果有人遇到过同样的问题:
问题是我通过使用@Context UriInfo uriInfo
通过注入的.getAbsolutePathBuilder()
创建了位置标头。
该方法在同步服务器中有效,因为访问UriInfo的线程仍然具有相同的Request上下文。
但是,当我切换到异步方法时,最终必须访问Runnable
的基础uriInfo.getAbsolutePathBuilder()
不在任何上下文中-因此会引发异常,从而停止进一步执行。
解决方法:
在任何应返回位置标头的异步方法中,I .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();
}