亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

使用ETags減少Web應(yīng)用帶寬和負(fù)載第2/2頁(yè)

 更新時(shí)間:2008年01月10日 19:09:38   作者:  
使用ETags減少Web應(yīng)用帶寬和負(fù)載

清單 1:ETagContentFilter.doFilter

你需注意到,我們還設(shè)置了Last-Modified頭。這被認(rèn)為是為服務(wù)器產(chǎn)生內(nèi)容的正確形式,因?yàn)槠溆狭瞬徽J(rèn)識(shí)ETag頭的客戶端。

下面的例子使用了一個(gè)工具類EtagComputeUtils來(lái)產(chǎn)生對(duì)象所對(duì)應(yīng)的字節(jié)數(shù)組,并處理MD5摘要邏輯。我使用了javax.security MessageDigest來(lái)計(jì)算MD5哈希碼。

public static byte[] serialize(Object obj) throws IOException {
byte[] byteArray = null;
ByteArrayOutputStream baos = null;
ObjectOutputStream out = null;
try {
// These objects are closed in the finally.
baos = new ByteArrayOutputStream();
out = new ObjectOutputStream(baos);
out.writeObject(obj);
byteArray = baos.toByteArray();
} finally {
if (out != null) {
out.close();
}
}
return byteArray;
}

public static String getMd5Digest(byte[] bytes) {
MessageDigest md;
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("MD5 cryptographic algorithm is not available.", e);
}
byte[] messageDigest = md.digest(bytes);
BigInteger number = new BigInteger(1, messageDigest);
// prepend a zero to get a "proper" MD5 hash value
StringBuffer sb = new StringBuffer('0');
sb.append(number.toString(16));
return sb.toString();
}

清單 2:ETagComputeUtils

直接在web.xml中配置filter。

  <filter>
<filter-name>ETag Content Filter</filter-name>
<filter-class>org.springframework.samples.petclinic.web.ETagContentFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>ETag Content Filter</filter-name>
<url-pattern>/*.htm</url-pattern>
</filter-mapping>

清單 3:web.xml中配置filter。

每個(gè).htm文件將被EtagContentFilter過(guò)濾,如果頁(yè)面自上次客戶端請(qǐng)求后沒(méi)有改變,它將返回一個(gè)空內(nèi)容體的HTTP響應(yīng)。

我們?cè)谶@里展示的方法對(duì)特定類型的頁(yè)面是有用的。但是,該方法有兩個(gè)缺點(diǎn):

  • 我們是在頁(yè)面已經(jīng)被展現(xiàn)在服務(wù)器之后計(jì)算ETag的,但是在返回客戶端之前。如果有Etag匹配,實(shí)際上并不需要再為model裝進(jìn)數(shù)據(jù),因?yàn)橐宫F(xiàn)的頁(yè)面不需要發(fā)送回客戶端。
  • 對(duì)于類似于在頁(yè)腳顯示日期時(shí)間這樣的頁(yè)面,即使內(nèi)容實(shí)際上并沒(méi)有改變,每個(gè)頁(yè)面也將是不同的。

下一節(jié),我們將著眼于另一種方法,其通過(guò)理解更多關(guān)于構(gòu)造頁(yè)面的底層數(shù)據(jù)來(lái)克服這些問(wèn)題的某些限制。

ETag攔截器(Interceptor)

Spring MVC HTTP 請(qǐng)求處理途徑中包括了在一個(gè)controller前插接攔截器(Interceptor)的能力,因而有機(jī)會(huì)處理請(qǐng)求。這兒是應(yīng)用我們ETag比較邏輯的理想場(chǎng)所,因此如果我們發(fā)現(xiàn)構(gòu)建一個(gè)頁(yè)面的數(shù)據(jù)沒(méi)有發(fā)生變化,我們可以避免進(jìn)一步處理。

這兒的訣竅是你怎么知道構(gòu)成頁(yè)面的數(shù)據(jù)已經(jīng)改變了?為了達(dá)到本文的目的,我創(chuàng)建了一個(gè)簡(jiǎn)單的ModifiedObjectTracker,它通過(guò)Hibernate事件偵聽(tīng)器清楚地知道插入、更新和刪除操作。該追蹤器為應(yīng)用程序的每個(gè)view維護(hù)一個(gè)唯一的號(hào)碼,以及一個(gè)關(guān)于哪些Hibernate實(shí)體影響每個(gè)view的映射。每當(dāng)一個(gè)POJO被改變了,使用了該實(shí)體的view的計(jì)數(shù)器就加1。我們使用該計(jì)數(shù)值作為ETag,這樣當(dāng)客戶端將ETag送回時(shí)我們就知道頁(yè)面背后的一個(gè)或多個(gè)對(duì)象是否被修改了。

代碼

我們就從ModifiedObjectTracker開(kāi)始吧:

public interface ModifiedObjectTracker {
void notifyModified(> String entity);
}

夠簡(jiǎn)單吧?這個(gè)實(shí)現(xiàn)還有一點(diǎn)更有趣的。任何時(shí)候一個(gè)實(shí)體改變了,我們就更新每個(gè)受其影響的view的計(jì)數(shù)器:

public void notifyModified(String entity) {
// entityViewMap is a map of entity -> list of view names
List views = getEntityViewMap().get(entity);

if (views == null) {
return; // no views are configured for this entity
}

synchronized (counts) {
for (String view : views) {
Integer count = counts.get(view);
counts.put(view, ++count);
}
}
}

一個(gè)“改變”就是插入、更新或者刪除。這里給出的是偵聽(tīng)刪除操作的處理器(配置為Hibernate 3 LocalSessionFactoryBean上的事件偵聽(tīng)器):

public class DeleteHandler extends DefaultDeleteEventListener {
private ModifiedObjectTracker tracker;

public void onDelete(DeleteEvent event) throws HibernateException {
getModifiedObjectTracker().notifyModified(event.getEntityName());
}

public ModifiedObjectTracker getModifiedObjectTracker() {
return tracker;
}
public void setModifiedObjectTracker(ModifiedObjectTracker tracker) {
this.tracker = tracker;
}
}

ModifiedObjectTracker通過(guò)Spring配置被注入到DeleteHandler中。還有一個(gè)SaveOrUpdateHandler來(lái)處理新建或更新POJO。

如果客戶端發(fā)送回當(dāng)前有效的ETag(意味著自上次請(qǐng)求之后我們的內(nèi)容沒(méi)有改變),我們將阻止更多的處理,以實(shí)現(xiàn)我們的性能提升。在Spring MVC里,我們可以使用HandlerInterceptorAdaptor并覆蓋preHandle方法:

public final boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws
ServletException, IOException {
String method = request.getMethod();
if (!"GET".equals(method))
return true;

String previousToken = request.getHeader("If-None-Match");
String token = getTokenFactory().getToken(request);

// compare previous token with current one
if ((token != null) && (previousToken != null && previousToken.equals('"' + token + '"'))) {
response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
// re-use original last modified timestamp
response.setHeader("Last-Modified", request.getHeader("If-Modified-Since"))
return false; // no further processing required
}

// set header for the next time the client calls
if (token != null) {
response.setHeader("ETag", '"' + token + '"');

// first time through - set last modified time to now
Calendar cal = Calendar.getInstance();
cal.set(Calendar.MILLISECOND, 0);
Date lastModified = cal.getTime();
response.setDateHeader("Last-Modified", lastModified.getTime());
}

return true;
}

我們首先確信我們正在處理GET請(qǐng)求(與PUT一起的ETag可以用來(lái)檢測(cè)不一致的更新,但其超出了本文的范圍。)。如果該記號(hào)與上次我們發(fā)送的記號(hào)相匹配,我們返回一個(gè)“304未修改”響應(yīng)并“短路”請(qǐng)求處理鏈的其余部分。否則,我們?cè)O(shè)置ETag響應(yīng)頭以便為下一次客戶端請(qǐng)求做好準(zhǔn)備。

你需注意到我們將產(chǎn)生記號(hào)邏輯抽出到一個(gè)接口中,這樣可以插接不同的實(shí)現(xiàn)。該接口有一個(gè)方法:

public interface ETagTokenFactory {
String getToken(HttpServletRequest request);
}

為了把代碼清單減至最小,SampleTokenFactory的簡(jiǎn)單實(shí)現(xiàn)還擔(dān)當(dāng)了ETagTokenFactory的角色。本例中,我們通過(guò)簡(jiǎn)單返回請(qǐng)求URI的更改計(jì)數(shù)值來(lái)產(chǎn)生記號(hào):

public String getToken(HttpServletRequest request) {
String view = request.getRequestURI();
Integer count = counts.get(view);
if (count == null) {
return null;
}

return count.toString();
}

大功告成!

會(huì)話

這里,如果什么也沒(méi)改變,我們的攔截器將阻止任何搜集數(shù)據(jù)或展現(xiàn)view的開(kāi)銷(xiāo)。現(xiàn)在,讓我們看看HTTP頭(借助于LiveHTTPHeaders),看看到底發(fā)生了什么。下載文件中包含了配置該攔截器的說(shuō)明,因此owner.htm“能夠使用ETag”:

我們發(fā)起的第一個(gè)請(qǐng)求說(shuō)明該用戶已經(jīng)看過(guò)了這個(gè)頁(yè)面:

---------------------------------------------------------- 
http://localhost:8080/petclinic/owner.htm?ownerId=10

GET /petclinic/owner.htm?ownerId=10 HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.0.4
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cookie: JSESSIONID=13D2E0CB63897F4EDB56639E46D2BBD8
X-lori-time-1: 1182364348062
If-Modified-Since: Wed, 20 Jun 2007 18:29:03 GMT
If-None-Match: "-1"

HTTP/1.x 304 Not Modified
Server: Apache-Coyote/1.1
Date: Wed, 20 Jun 2007 18:32:30 GMT

我們現(xiàn)在應(yīng)該做點(diǎn)修改,看看ETag是否改變了。我們給這個(gè)物主增加一個(gè)寵物:

----------------------------------------------------------
http://localhost:8080/petclinic/addPet.htm?ownerId=10

GET /petclinic/addPet.htm?ownerId=10 HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.0.4
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost:8080/petclinic/owner.htm?ownerId=10
Cookie: JSESSIONID=13D2E0CB63897F4EDB56639E46D2BBD8
X-lori-time-1: 1182364356265

HTTP/1.x 200 OK
Server: Apache-Coyote/1.1
Pragma: No-cache
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Cache-Control: no-cache, no-store
Content-Type: text/html;charset=ISO-8859-1
Content-Language: en-US
Content-Length: 2174
Date: Wed, 20 Jun 2007 18:32:57 GMT
----------------------------------------------------------
http://localhost:8080/petclinic/addPet.htm?ownerId=10

POST /petclinic/addPet.htm?ownerId=10 HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.0.4
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost:8080/petclinic/addPet.htm?ownerId=10
Cookie: JSESSIONID=13D2E0CB63897F4EDB56639E46D2BBD8
X-lori-time-1: 1182364402968
Content-Type: application/x-www-form-urlencoded
Content-Length: 40
name=Noddy&birthDate=1000-11-11&typeId=5
HTTP/1.x 302 Moved Temporarily
Server: Apache-Coyote/1.1
Pragma: No-cache
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Cache-Control: no-cache, no-store
Location: http://localhost:8080/petclinic/owner.htm?ownerId=10
Content-Language: en-US
Content-Length: 0
Date: Wed, 20 Jun 2007 18:33:23 GMT

因?yàn)閷?duì)addPet.htm我們沒(méi)有配置任何已知ETag,也沒(méi)有設(shè)置頭信息?,F(xiàn)在,我們?cè)僖淮尾榭磇d為10的物主。注意ETag這時(shí)是1:

----------------------------------------------------------
http://localhost:8080/petclinic/owner.htm?ownerId=10

GET /petclinic/owner.htm?ownerId=10 HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.0.4
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost:8080/petclinic/addPet.htm?ownerId=10
Cookie: JSESSIONID=13D2E0CB63897F4EDB56639E46D2BBD8
X-lori-time-1: 1182364403109
If-Modified-Since: Wed, 20 Jun 2007 18:29:03 GMT
If-None-Match: "-1"

HTTP/1.x 200 OK
Server: Apache-Coyote/1.1
Etag: "1"
Last-Modified: Wed, 20 Jun 2007 18:33:36 GMT
Content-Type: text/html;charset=ISO-8859-1
Content-Language: en-US
Content-Length: 4317
Date: Wed, 20 Jun 2007 18:33:45 GMT

最后,我們?cè)俅尾榭磇d為10的物主。這次我們的ETag命中了,我們得到一個(gè)“304未修改”響應(yīng):

----------------------------------------------------------
http://localhost:8080/petclinic/owner.htm?ownerId=10

GET /petclinic/owner.htm?ownerId=10 HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.0.4
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cookie: JSESSIONID=13D2E0CB63897F4EDB56639E46D2BBD8
X-lori-time-1: 1182364493500
If-Modified-Since: Wed, 20 Jun 2007 18:33:36 GMT
If-None-Match: "1"

HTTP/1.x 304 Not Modified
Server: Apache-Coyote/1.1
Date: Wed, 20 Jun 2007 18:34:55 GMT

我們已經(jīng)利用HTTP緩存節(jié)約了帶寬和計(jì)算時(shí)間!

細(xì)粒度印記(The Fine Print):實(shí)踐中,我們可以通過(guò)以更細(xì)粒度的跟蹤對(duì)象變化來(lái)獲得更大的功效,例如使用對(duì)象id。然而,這種使修改對(duì)象關(guān)聯(lián)到view上的想法高度依賴應(yīng)用程序的整體數(shù)據(jù)模型設(shè)計(jì)。這里的實(shí)現(xiàn)(ModifiedObjectTracker)是說(shuō)明性的,有意為更多的探索提供想法。它并不是旨在生產(chǎn)環(huán)境中使用(比如它在簇中使用還不穩(wěn)定)。一個(gè)可選的更深的考慮是使用數(shù)據(jù)庫(kù)觸發(fā)器來(lái)跟蹤變化,讓攔截器訪問(wèn)觸發(fā)器所寫(xiě)入的表。

結(jié)論

我們已經(jīng)看了兩種使用ETag減少帶寬和計(jì)算的方法。我希望本文已為你當(dāng)下或?qū)?lái)基于Web的項(xiàng)目提供了精神食糧,并正確評(píng)價(jià)在底層利用ETag響應(yīng)頭的做法。

正如牛頓(Isaac Newton)的名言所說(shuō):“如果說(shuō)我看得更遠(yuǎn),那是因?yàn)槲艺驹诰奕说募绨蛏?。”REST風(fēng)格應(yīng)用的核心是簡(jiǎn)單、好的軟件設(shè)計(jì)、不要重新發(fā)明輪子。我相信隨著使用量和知名度的增長(zhǎng),針對(duì)基于Web應(yīng)用的REST風(fēng)格架構(gòu)有益于主流應(yīng)用開(kāi)發(fā)的遷移,我期盼著它在我將來(lái)的項(xiàng)目中發(fā)揮更大的作用。

關(guān)于作者

Gavin Terrill 是BPS公司的首席技術(shù)執(zhí)行官。Gavin已經(jīng)有20多年的軟件開(kāi)發(fā)歷史了,擅長(zhǎng)企業(yè)Java應(yīng)用程序,但仍拒絕扔掉他的TRS-80。閑暇時(shí)間Gavin喜歡航海、釣魚(yú)、玩吉他、品紅酒(不分先后順序)。

感謝

我要感謝我的同事Patrick Bourke和Erick Dorvale的幫助,他們對(duì)這篇文章提供的反饋意見(jiàn)。

代碼和說(shuō)明可以從這里下載。

查看英文原文:Using ETags to Reduce Bandwith & Workload with Spring & Hibernate

相關(guān)文章

  • PHP加密解密實(shí)例分析

    PHP加密解密實(shí)例分析

    這篇文章主要介紹了PHP加密解密實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了PHP自定義函數(shù)實(shí)現(xiàn)字符串加密與對(duì)應(yīng)解密的相關(guān)技巧,需要的朋友可以參考下
    2015-12-12
  • PHP實(shí)現(xiàn)刪除多重?cái)?shù)組對(duì)象屬性并重新賦值的方法

    PHP實(shí)現(xiàn)刪除多重?cái)?shù)組對(duì)象屬性并重新賦值的方法

    這篇文章主要介紹了PHP實(shí)現(xiàn)刪除多重?cái)?shù)組對(duì)象屬性并重新賦值的方法,涉及php結(jié)合sphinx操作數(shù)組元素的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2017-06-06
  • php使用json-schema模塊實(shí)現(xiàn)json校驗(yàn)示例

    php使用json-schema模塊實(shí)現(xiàn)json校驗(yàn)示例

    這篇文章主要介紹了php使用json-schema模塊實(shí)現(xiàn)json校驗(yàn),結(jié)合實(shí)例形式分析了json-schema模塊的安裝及使用json-schema模塊進(jìn)行json校驗(yàn)的相關(guān)操作技巧,需要的朋友可以參考下
    2019-09-09
  • php join函數(shù)應(yīng)用

    php join函數(shù)應(yīng)用

    php join函數(shù)應(yīng)用,需要的朋友可以參考下。
    2011-05-05
  • php實(shí)現(xiàn)的返回?cái)?shù)據(jù)格式化類實(shí)例

    php實(shí)現(xiàn)的返回?cái)?shù)據(jù)格式化類實(shí)例

    這篇文章主要介紹了php實(shí)現(xiàn)的返回?cái)?shù)據(jù)格式化類及其應(yīng)用實(shí)例,包括針對(duì)XML、JSON等的格式化,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2014-09-09
  • PHP 文件寫(xiě)入和讀取操作實(shí)例詳解【必看篇】

    PHP 文件寫(xiě)入和讀取操作實(shí)例詳解【必看篇】

    這篇文章主要介紹了PHP 文件寫(xiě)入和讀取操作,結(jié)合實(shí)例形式詳細(xì)分析了PHP針對(duì)文件的打開(kāi)、讀取、寫(xiě)入及指針操作相關(guān)使用技巧,需要的朋友可以參考下
    2019-11-11
  • mysql5的sql文件導(dǎo)入到mysql4的方法

    mysql5的sql文件導(dǎo)入到mysql4的方法

    有時(shí)候用到將高版本的數(shù)據(jù)庫(kù)轉(zhuǎn)移到低版本的數(shù)據(jù)庫(kù)中,下面是mysql5數(shù)據(jù)轉(zhuǎn)到mysql4的方法
    2008-10-10
  • PHP面向?qū)ο蠛兔嫦蜻^(guò)程的區(qū)別詳解

    PHP面向?qū)ο蠛兔嫦蜻^(guò)程的區(qū)別詳解

    這篇文章主要給大家介紹了PHP面向?qū)ο蠛兔嫦蜻^(guò)程的區(qū)別,面向過(guò)程編程是將代碼組織為一系列函數(shù)或過(guò)程,面向?qū)ο缶幊淌菍⒋a組織為對(duì)象,其中包含屬性和方法,還有不懂的朋友可以參考閱讀本文
    2023-11-11
  • PHP面向?qū)ο缶偨Y(jié)

    PHP面向?qū)ο缶偨Y(jié)

    這篇文章主要介紹了PHP面向?qū)ο缶?較為詳細(xì)的介紹了PHP面向?qū)ο蟪绦蛟O(shè)計(jì)中的各種概念與常見(jiàn)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2014-11-11
  • php英文單詞統(tǒng)計(jì)器

    php英文單詞統(tǒng)計(jì)器

    這篇文章主要為大家詳細(xì)介紹了php英文單詞統(tǒng)計(jì)器的實(shí)現(xiàn)代碼,
    2016-06-06

最新評(píng)論