在PL/SQL應(yīng)用程序中緩存圖片

字號(hào):

在使用基于PL/SQL的web應(yīng)用程序時(shí),mod_plsql的一個(gè)非常令人煩惱的方面是當(dāng)你在數(shù)據(jù)庫(kù)外使用圖片時(shí),你的瀏覽器似乎從不對(duì)它們進(jìn)行緩存。使用過(guò)Cache-Control、Expires和Last-Modified頭,但是似乎都不起作用。每一次重新加載頁(yè)面時(shí),瀏覽器就會(huì)重新加載所有從mod_plsql而來(lái)的圖片,但是它會(huì)將從文件系統(tǒng)而來(lái)的圖片從緩存中獲得。這使得對(duì)于終端用戶來(lái)說(shuō)如果頁(yè)面擁有大量圖片的話頁(yè)面會(huì)顯得非常緩慢,而這些圖片是可以被緩存的。
    對(duì)于要使用大量存儲(chǔ)在數(shù)據(jù)庫(kù)中圖片的項(xiàng)目來(lái)說(shuō),要解決這個(gè)緩存問(wèn)題,可以使用Java將這些圖片寫到文件系統(tǒng)上,這樣Apache就可以以被緩存的方式來(lái)使用它們了。在這么做之前,先使用Firebug和Wireshark來(lái)作些跟蹤。關(guān)于這些工具有些事要注意。當(dāng)使用Firebug>Net>Images來(lái)跟蹤圖片緩存時(shí),一個(gè)淺灰色條顯示一個(gè)緩存的圖片而一個(gè)深灰色條顯示非緩存圖片。當(dāng)使用wireshark時(shí),右鍵單擊相應(yīng)的捕獲包,例如一個(gè)圖片的Get,然后選擇“FollowT CP Stream”。這會(huì)按順序顯示給你這個(gè)包流。
    我從跟蹤Apache的一個(gè)靜態(tài)頁(yè)開(kāi)始,它包含一些從文件系統(tǒng)而來(lái)的圖片。我發(fā)現(xiàn)每一次重新加載頁(yè)面的時(shí)候,瀏覽器都會(huì)重新提交相同的“Get”請(qǐng)求,當(dāng)我按shift+refresh或是簡(jiǎn)單地刷新時(shí),會(huì)相應(yīng)地返回一個(gè)非緩存頁(yè)面或緩存頁(yè)面。一個(gè)問(wèn)題是“If-Modified-Since”和“If-None-Match”頭只在緩存頁(yè)面上,不過(guò)我將采用緩存頁(yè)面。所以,瀏覽器每次都請(qǐng)求圖片(或文件),這意味著它不會(huì)緩存這些圖片。所以,我是在服務(wù)器端丟了些東西。
    下面的例子是Firefox和Apache之間的一個(gè)虛擬對(duì)話:
    Firefox:獲得logo.gif
    Apache:HTTP200“OK”了, Etag:ABC123,Content-Length: 35, gif文件內(nèi)容
    Firefox:Get logo.gif,If-None-Match:ABC123
    Apache:HTTP304“Not Modified”, Etag:ABC123,Content-Length:35, 頭關(guān)閉了,沒(méi)有文件返回
    對(duì)于第一個(gè)對(duì)logo.gif的請(qǐng)求,Apache返回了一個(gè)Etag頭和這個(gè)文件的內(nèi)容。對(duì)于第二個(gè)請(qǐng)求,F(xiàn)irefox發(fā)送了Etag的值作為If-None-Match頭。Apache比較了這些值并簡(jiǎn)單地返回了一個(gè)304狀態(tài),而不是圖片,因?yàn)橹凳且粯拥摹?BR>    什么是ETag?它是一個(gè)用于某個(gè)文件的標(biāo)識(shí)符,文件改變時(shí)它也要改變。它的相應(yīng)請(qǐng)求頭是“If-None-Match”??梢栽凇癓ast-Modified”響應(yīng)頭和“If-Modified-Since”請(qǐng)求頭之間做相同的對(duì)比。HTTP規(guī)范認(rèn)為Etag是一個(gè)“強(qiáng)”屬性而“Last-Modified”是一個(gè)“弱”屬性,所以我在這里將關(guān)注于Etag。
    所以,以前我們一直希望Apache或mod_plsql能夠緩存我們的圖片,但實(shí)際上我們(PL/SQL程序員)是要做這個(gè)緩存的人。不過(guò)幸好它很簡(jiǎn)單,特別是現(xiàn)在你已了解了這個(gè)問(wèn)題。
    為了使其起作用,你需要做3件事:
    使If-None-Match CGI環(huán)境變量可用于mod_plsq或內(nèi)嵌網(wǎng)關(guān)。
    將包含所有圖片請(qǐng)求的Etag頭發(fā)送回去。
    當(dāng)有一個(gè)圖片請(qǐng)求時(shí),比較Etag和If-None-Match頭,返回一個(gè)304 Not Modified頭或者返回這個(gè)圖片。
    如果你使用內(nèi)嵌的PL/SQL網(wǎng)關(guān),那么以SYS權(quán)限執(zhí)行下面的代碼添加2個(gè)CGI環(huán)境變量:
    如果你在使用Oracle HTTP服務(wù)器(Apache+mod_plsql),那么添加下面的代碼到你的Database Access Descriptor(數(shù)據(jù)訪問(wèn)描述符,DAD)中,然后啟動(dòng)OHS來(lái)應(yīng)用你的改變:
    PlsqlCGIEnvironmentList HTTP_IF_NONE_MATCH
    PlsqlCGIEnvironmentList IF_MODIFIED_SINCE
    OK,現(xiàn)在看下代碼:
    27-35行很重要,我們確定這個(gè)圖片/文件是否改變了,并簡(jiǎn)單地返回一個(gè)304狀態(tài)代碼,而不是圖片本身。注意我通過(guò)連接主鍵和最近更新/創(chuàng)建的日期(格式化為具有時(shí)間的Julian日期)來(lái)構(gòu)建Etag頭。這意味著如果這個(gè)圖片或文件被更新了,那么日期就會(huì)改變,從而改變Etag。這反過(guò)來(lái)使你的瀏覽器可以下載更新的版本。