Http缓存

过滤器是非常有用的,比如Http缓存协议的实现就可以基于过滤器来做。

在AndServer中,有一个HttpCacheFilter类,它实现了Http缓存协议部分,下面是它实现的几个关键头:

  • Cache-Control
  • Last-Modified
  • If-Modified-Since
  • If-Unmodified-Since
  • ETag
  • If-None-Match

用法

比如我们100%建议开启Website的缓存,它能提高用来提高服务器性能,尤其像AndServer这种运行在手机端的服务器。

Server server = AndServer.serverBuilder()
    ...
    .filter(new HttpCacheFilter())
    .build();

...

如上述代码即可打开AndServer自带的几个Website的缓存:

  • AssetsWebsite
  • StorageWebsite

Http缓存协议

我们先来认识AndServer中的两个Interface:

  1. LastModified,用来支持响应头的Last-Modified和请求头的If-Modified-Since
  2. ETag,用来支持响应头的ETag和请求头的If-None-Match

关于上述两个Http头的概念,如果大家还有疑问请Google搜索相关资料了解。

每个接口的数据肯定是又唯一属性的,所以要保证每一个接口的数据都有一个唯一ID。LastModified接口是返回当前接口指向资源的修改时间的,ETag接口是返回当前接口指向资源的唯一值的。唯一值这个概念可能比较难理解,因为Http没有规定ETag的值是资源的什么属性,比如HashCodeMD5等等都可以作为一个唯一属性。

LastModified

此接口返回当前资源的修改时间(Last-Modified响应头),客户端检测到这个响应头时会缓存当前接口的响应数据。客户端再次请求当前资源时,会带上上次请求此接口返回的修改时间(If-Modified-Since相应头),服务器会用If-Modified-Since和服务器上资源的修改时间做对比。如果If-Modified-Since大于等于服务器资源的修改时间,那么返回304响应码,没有任何响应包体,客户端将会使用上次缓存的数据;如果If-Modified-Since小于服务器资源的修改时间,说明自上次请求之后,此资源已经被修改过了,也就是服务器的资源比客户端的资源新,服务器此时返回响应码200,返回新的资源作为响应包体。

ETag

一般情况下我们只要开启LastModified即可,那么ETag又是做什么的呢?因为Unix时间戳是按照秒计算的,所以Http中的时间都是秒,或者说表示毫秒的三位都是0。由此可见,如果当前接口指向的资源在1秒内被修改,那么客户端将拿不到最新的资源。所以介于此,Http添加了ETag来兼容Last-Modified,Http协议固定ETag的值应该是粒度的值,也就是说它比Last-Modified更加细化。

RequestHandler如何使用缓存

如果开发者设置了HttpCacheFilter为AndServer的过滤器,那么为RequestHandler开启缓存功能将会很简单,不用自己在Response中设置任何头。

public class MyHandler implement RequestHandler, LastModified {

    public void handle(HttpRequest request, HttpResponse response, HttpContext context)
            throws HttpException, IOException {
        // 比如当前资源是个File。
        String path = HttpRequestParser.getRequestPath(request);
        ... // 一些判断此资源是个文件。

        File file = new File(path);
        response.setStatusCode(200);
        response.setEntity(new FileEntity(file));
    }

    @Ovrride
    public long getLastModified(HttpRequest request) ... {
        // 比如当前资源是个File。
        String path = HttpRequestParser.getRequestPath(request);
        ... // 一些判断此资源是个文件。

        File file = new File(path);
        return file.lastModified();
    }
}

比如对某个文件做了缓存支持,以当前文件的Last-Modified为唯一性的判断依据还不够,那么我们应该实现ETag接口,返回这个文件的更详细的唯一属性。

关于ETag的建议:建议返回当前文件的MD5值,并做一些格式上的处理,这样基本可以做到99.99%的唯一性。当文件的内容被修改(包括在1秒内修改)时,文件的MD5会立刻发生变化。当然对于普通接口也是一样,可以返回要返回内容的MD5值(或者其它粒度唯一属性也可以)。

public class MyHandler implement RequestHandler, LastModified {

    public void handle(HttpRequest request, HttpResponse response, HttpContext context)
            throws HttpException, IOException {
        // 同上...
    }

    @Ovrride
    public long getLastModified(HttpRequest request) throws HttpException, IOException {
        // 同上...
    }

    @Ovrride
    public String getETag(HttpRequest request) throws HttpException, IOException {
        // 比如当前资源是个File。
        String path = HttpRequestParser.getRequestPath(request);
        ... // 一些判断此资源是个文件。

        File file = new File(path);

        // 返回当前文件的MD5值。
        InputStream inStream = new FileInpuStream(file);
        return DigestUtils.md5DigestAsHex(inStream);
    }
}

results matching ""

    No results matching ""