我应该在 Restlet 中手动 return 304 响应缓存请求(ETag)吗?

Should I manually return 304 response for cached requests (ETag) in Restlet?

我向我的应用程序添加了自定义缓存行为,类似于 Thierry 提出的 in this article。对于静态内容中的每个 CSS、JS 和 HTML 文件服务器,我添加了以下两个 headers:

// Added by me
ETag: "0c635aa7113262fac7606da2432e00f5" // md5(last_mod_date_of_file)
Cache-Control: max-age=31536000 // one year

// Automatically added by Restlet (probably Directory class?)
Date: Wed, 09 Nov 2016 11:50:53 GMT
Expires: Wed, 09 Nov 2016 12:00:53 GMT
Last-Modified: Wed, 09 Nov 2016 17:30:56 GMT

这工作正常,但我注意到在测试服务器上部署代码并在 Chrome 中点击 F5 后,我再次获取整个 body 响应(使用HTTP 200 returned).

我注意到那些请求也使用了正确的 headers:

Cache-Control:max-age=0
If-Modified-Since: Wed, 09 Nov 2016 17:30:56 GMT
If-None-Match: "0c635aa7113262fac7606da2432e00f5"

我的问题是,我是否应该在我的服务器过滤器中对 If-None-Match header 和 return 304 响应进行任何手动验证然后?还是由 Restlet 处理?

注意:这个问题有点奇怪的是它似乎在我的本地开发环境中工作正常。我也有点困惑为什么 Expires 被 Restlet 设置为 之前 Last-Modified 的日期。如果这是罪魁祸首,我会尝试调试,但这不会使我关于手动设置 304 状态和检查服务器上的 ETag 的问题无效。

好的,所以我已经弄明白了,我在下面发布了答案。

我是否应该在我的服务器过滤器中手动验证 If-None-Match header 然后 return 304 响应?

不,您不必自己手动执行此操作。这由 Restlet 自动处理(DirectoryServerResource 负责)。

那是什么问题?

问题确实出在 Last-Modified header 被设置为未来的日期。发生这种情况是因为我的生产服务器在 UTC-8 时区,而我在 UTC+1.

进行开发

我是怎么解决的?

它需要熟悉 Restlet API,但当时的解决方案很简单。我确保当我的应用程序启动时,它会从操作系统读取我的应用程序目录的 File Last Modified 属性,因为这是我想在 Last-Modified header 中使用的值。 现在,您不能只在 Filter 中的 response 上设置此 header,因为 HTTP 缓存 header 的自动处理发生在提到的 [=12] 之前=] class。所以解决方案如下:

创建一个扩展 DSR 的 class(免费为您提供所有自动缓存处理)并修改其 handle() 方法,以便在 Last-Modified header 之前设置这个逻辑开始了:

 public class WebAssetsResource extends DirectoryServerResource {
    @Override
    public Representation handle() {
        Date desiredDate = ...; // I read this from File System
        getInfo().setModificationDate(desiredDate);
        return super.handle(); // Automatic logic will use desired date
    }
 }

现在,确保您新创建的资源被自定义使用 Directory class。

public class CachedWebAssetsDirectory extends Directory {
    public CachedWebAssetsDirectory(Context context, Reference rootLocalReference) {
        super(context, rootLocalReference);
        setTargetClass(WebAssetsResource.class); // Needed so that Restlet will use our implementation of a ServerResource to serve static files
    }
}

之后您可以根据需要使用 CachedWebAssetsDirectory,在此基础上构建任何自定义过滤器。