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