Nic*_*tto 9 java jax-rs jersey resteasy quarkus
在将我的 JAX-RS 应用程序从 Jersey 迁移到 Quarkus/Resteasy 时,我发现方法发生了行为变化evaluatePreconditions(Date lastModified)。事实上,在我的用例中,最后修改日期包含毫秒,不幸的是标题的日期格式If-Modified-Since并且Last-Modified不支持毫秒,正如我们在RFC 2616 中看到的那样。
Jersey 从提供的日期(正如我们在这里看到的)修剪毫秒数,而在 Resteasy 中,日期没有被修改,所以它实际上If-Modified-Since以不同的精度(分别是秒和毫秒)比较日期(来自标题的日期和提供的日期)以不匹配而告终,因此是 HTTP 状态代码200。
说明问题的代码:
@Path("/evaluatePreconditions")
public class EvaluatePreconditionsResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public Response findData(@Context Request request) {
final Data data = retrieveData();
final Date lastModified = Timestamp.valueOf(data.getLastModified());
final Response.ResponseBuilder responseBuilder =
request.evaluatePreconditions(lastModified);
if (responseBuilder == null) {
// Last modified date didn't match, send new content
return Response.ok(data.toString())
.lastModified(lastModified)
.build();
}
// Sending 304 not modified
return responseBuilder.build();
}
private Data retrieveData() {
// Let's assume that we call a service here that provides this value
// The date time is expressed in GMT+2, please adjust it according
// to your timezone
return new Data(
LocalDateTime.of(2020, 10, 2, 10, 23, 16, 1_000_000),
"This is my content"
);
}
public static class Data {
private final LocalDateTime lastModified;
private final String content;
public Data(LocalDateTime lastModified, String content) {
this.lastModified = lastModified;
this.content = content;
}
public LocalDateTime getLastModified() {
return lastModified;
}
@Override
public String toString() {
return content;
}
}
}
Run Code Online (Sandbox Code Playgroud)
与 Jersey 对应的结果:
curl -H "If-Modified-Since: Fri, 02 Oct 2020 08:23:16 GMT" \
-I localhost:8080/evaluatePreconditions
HTTP/1.1 304 Not Modified
...
Run Code Online (Sandbox Code Playgroud)
Quarkus/Resteasy 对应的结果:
curl -H "If-Modified-Since: Fri, 02 Oct 2020 08:23:16 GMT" \
-I localhost:8080/evaluatePreconditions
HTTP/1.1 200 OK
Last-Modified: Fri, 02 Oct 2020 08:23:16 GMT
...
Run Code Online (Sandbox Code Playgroud)
这种行为已经提出在RestEasy的项目,但对于球队,修剪日期将增加一个新的错误,因为如果数据/资源在同一秒内多次修改,我们会得到一个304,如果我们修剪日期,200如果我们没有,这是一个公平的观点。但是,我可能错了,但根据我从RFC 7232 中的理解,如果可以在同一秒内发生多次修改,我们也应该依赖ETag,这意味着在 JAX-RS 规范中,我们应该使用evaluatePreconditions(Date lastModified, EntityTag eTag)反而。
那么根据 JAX-RS 规范关于这个特殊情况的正确行为是什么?
Request.evaluatePreconditions(Date lastModified)Resteasy 4.5的实现是错误的。org.jboss.resteasy.specimpl.RequestImpl类的实现依赖于辅助类DateUtil,它期望Last-Modified标头采用以下格式之一: RFC 1123 "EEE, dd MMM yyyy HH:mm:ss zzz"、 RFC 1036"EEEE, dd-MMM-yy HH:mm:ss zzz"或 ANSI C "EEE MMM d HH:mm:ss yyyy"。在这三种格式中,只有 ANSI C 列在RFC 7231 第 7.1.1.1 节中,并且它已过时。HTTP 1.1 的首选格式。标头按照RFC 5322 第 3.3 节中的规定,并且此格式不包含毫秒。Resteasy 实现引用的 RFC 1123 格式实际上来自RFC 822 第 5 节,但 RFC 822 适用于文本消息(邮件)而不适用于 HTTP 标头。Java 支持毫秒,Date但 HTTP 标头不支持。因此,比较不同精度的日期是一个错误。正确的实现是泽西岛的实现ContainerRequest,在比较之前将日期四舍五入到最接近的秒。
JAX-RS 规范 1.1在这方面没有具体说明。或者,至少,我没能找到它。JAX-RS 规范不需要解决这个问题。该实现必须按照 HTTP 规范处理 HTTP 标头,其中标头时间戳中不包括毫秒。
| 归档时间: |
|
| 查看次数: |
362 次 |
| 最近记录: |