Mongodb IsoDate 和 if-modified-since 在微服务上的问题

Mongodb IsoDate and the issue with if-modified-since on microservices

当我使用 spring 数据在我的 MongoDB 上插入文档时,我执行以下操作:

Update update = new Update();
update.currentDate("lastModified");
mongoTemplate.upsert(query, update, MyDocument.class);

我使用 MongoDB 的 currentDate,因为我想用我的 MongoDB 数据库所在的日期保存 MyDocument 的最后修改日期。

基于spec

The If-Modified-Since request-header field is used with a method to make it conditional: if the requested variant has not been modified since the time specified in this field, an entity will not be returned from the server; instead, a 304 (not modified) response will be returned without any message-body.

因此,保存此日期的目的是根据收到的日期验证 MyDocument 是否被修改。

因此,当我执行更新时,会在数据库上创建以下 IsoDate:

ISODate("2016-12-02T12:11:33.083Z")

因此,当客户想知道文档是否已更改时,他们将这个日期发回给我,然后我查询数据库:

    Query query = new Query(where("id").is(filter.getId()));
    Criteria criteria = Criteria.where("lastModified").gt(filter.getLastModified());
    query.addCriteria(criteria);
    return mongoTemplate.findOne(query, MyDocument.class);

除一个问题外,这非常有效:规范说明 header if-modified-since 具有以下格式:

If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT

这意味着 if-modified-since header 没有传递毫秒数。但是,MongoDB IsoDate 以毫秒保存当前日期。因此,当两个日期完全相同时,查询将不会 return 304 Not Modified,但会 return 整个资源,因为查询将是以下内容:

{ "id" : 123, "lastModified" : { "$gt" : { $java : 2016-12-02T12:11:39.000Z } } }

由于客户端不发送毫秒,java将毫秒设置为零(2016-12-02T12:11:39.000Z),意思就是 我数据库中的日期大于我的客户发送的日期:

2016-12-02T12:11:33.083Z > 2016-12-02T12:11:39.000Z

因为83毫秒。

最后一个问题是:解决这个问题的正确方法是什么,并且按照 if-modified-since 的规范建议正确工作?

您可以将最后修改日期毫秒设置为比较前的最大毫秒数这在技术上会抵消毫秒偏移量。

public static Date setMaxMillis(Date day,Calendar cal) {
    cal.setTime(day);
    cal.set(Calendar.MILLISECOND, cal.getMaximum(Calendar.MILLISECOND));
    return cal.getTime();
}

Query query = new Query(where("id").is(filter.getId()));
Criteria criteria = Criteria.where("lastModified").gt(setMaxMillis(filter.getLastModified(),Calendar.getInstance()));
query.addCriteria(criteria);
return mongoTemplate.findOne(query, MyDocument.class);