在上一个博客中,我们讨论了不同类型的缓存及其用例。
在本文中,我们将探讨如何利用HTTP响应标头和JAX-RS提供的支持来利用缓存。
过期标题
在HTTP 1.0中,一个名为Expires的简单响应头将告诉浏览器它可以缓存对象或页面多长时间。 在将来的某个日期之后,缓存将无效。 因此,如果我们进行API调用以检索数据:
GET /users/1
响应头为:
HTTP/1.1 200 OK
Content-Type: application/xml
Expires: Tue, 25 Aug 2013 16:00 GMT
-----
<user id="1">...</users>
这表示XML资料的有效期至格林尼治标准时间2013年8月25日16:00。
JAX-RS在javax.ws.rs.core.Response对象中支持此标头。
@Path("{id}")@GET@Produces(MediaType.APPLICATION_XML)public Response getUserXML(@PathParam("id") Long id){User user = userDB.get(id);ResponseBuilder builder = Response.ok(user,MediaType.APPLICATION_XML);//Putting expires header for HTTP broswer caching.Calendar cal = Calendar.getInstance();cal.set(2013,7,25,16,0);builder.expires(cal.getTime());return builder.build();}
但是,为了支持CDN,代理缓存和重新验证,需要具有功能更丰富,具有更明确控件的增强标题。 因此,在HTTP 1.1中,引入了一些新的标头,并对Expires进行了描述。 让我们探索它们。
缓存控制
Cache-Control有一组可变的逗号分隔指令,用于定义谁,如何以及可以缓存多长时间。 让我们探索其中的几个:
- – private / public :这是可访问性指令,private表示浏览器可以缓存对象,但代理或CDN不能,而public则使所有人均可访问。
- -无缓存,无存储,最大使用期限-很少有人用名字讲述故事。
JAX-RS提供javax.ws.rs.core.CacheControl类来表示此标头。
@Path("{id}")@GET@Produces(MediaType.APPLICATION_XML)public Response getUserXMLwithCacheControl(@PathParam("id") Long id){User user = userDB.get(id);CacheControl cc = new CacheControl();cc.setMaxAge(300);cc.setNoStore(true);cc.setPrivate(true);ResponseBuilder builder = Response.ok(user,MediaType.APPLICATION_XML);builder.cacheControl(cc);return builder.build();}
重新验证和条件GET :缓存过期后,缓存器可以重新验证缓存,向服务器发送请求以检查缓存是否陈旧或保持良好状态。 这是通过名为“ Last-Modified ”的标头完成的。
HTTP/1.1 200 OK
....
Cache-Control: max-age=1000
Last-Modified: Mon, 19 aug 2013 16:00 IST
要重新验证,必须发送带有标头“ If-modified-since ”的GET请求。这称为条件GET,如果数据被修改,则将发送具有当前资源值的响应代码200(OK)。 如果未修改数据,则发送响应代码“ 304”,这表示高速缓存仍然有效,此时可以更新“上次修改”标签。
埃塔格
Etag是另一个HTTP标头,可用于重新验证缓存,它通常是MD5哈希值。 服务器将响应中从资源生成的哈希作为Etag值发送,以便在验证时,客户端可以将其Etag值发送给服务器以检查驻留在服务器上的值是否匹配。(由于哈希是从资源生成的,因此请更改资源中会生成不同的哈希值)
对于此条件GET,发送带有标头“ If-none-Match”的请求以进行验证。
GET /users/23 HTTP/1.1
If-None-Match: "23432423423454654667444"
此外,根据不同的用例,我们可以具有强弱的Etag值。
JAX-RS为我们提供了相同的javax.ws.rs.core.EntityTag。
public class EntityTag {
.....
.....
为了帮助有条件的GET,JAX-RS还提供了一个可注入的帮助程序类Request,它具有以下方法:
....
ResponseBuilder evalutatePostConditions(EntityTag eTag);
ResponseBuilder evaluatePreConditions(Date isLastModified);
.....
比较请求标头中发送的etag或LastModified值。 让我们看一个例子……
@Path("{id}")@GET@Produces(MediaType.APPLICATION_XML)public Response getUserWithEtagSupport(@PathParam("id") Long id,@Context Request request){User user = userDB.get(id);//generating Etag out of hashCode of userEntityTag tag = new EntityTag(Integer.toString(user.hashCode()));CacheControl cc = new CacheControl();cc.setMaxAge(1000);ResponseBuilder builder = request.evaluatePreconditions(tag);if(builder!=null){//means the preconditions have been met and the cache is valid//we just need to reset the cachecontrol max age (optional)builder.cacheControl(cc);return builder.build();}//preconditions are not met and the cache is invalid//need to send new value with reponse code 200 (OK)builder = Response.ok(user,MediaType.APPLICATION_XML);//reset cache control and eTag (mandatory)builder.cacheControl(cc);builder.tag(tag);return builder.build();}
如果满足条件,则返回空值,这意味着最新标记和请求标头中提供的标记匹配,并且无需发送响应为OK的新数据。 发送“ 304”响应,表示未修改。
如果标签不匹配,则返回一个新的RequestBuilder对象,在其中设置新的etag和当前数据版本(在这种情况下为用户)。
这就是使用JAX-RS可以有效利用HTTP缓存发挥其全部潜力的方式。
翻译自: https://www.javacodegeeks.com/2013/10/http-caching-using-jax-rs.html