2010-05-01 62 views
5

我按照the docs中的建議將用戶上傳的圖像存儲在Google App Engine數據存儲區中,其格式爲db.Blob。然後我在/images/<id>.jpg上提供這些圖像。爲存儲在數據存儲區中的圖像發送「304未修改」

服務器總是發送一個200 OK響應,這意味着瀏覽器必須多次下載相同的圖像(==較慢),並且服務器必須多次發送相同的圖像(==更昂貴)。

由於大多數這些圖像可能永遠不會改變,我希望能夠發送一個304 Not Modified響應。我想計算某種當用戶上傳其照片的哈希值,然後使用該知道,如果用戶已經有此圖像中(也許發送哈希作爲Etag?)

我發現this answerthis answer解釋的邏輯相當好,但我有2個問題:

  1. 是否有可能在谷歌應用程序引擎發送Etag
  2. 有沒有人實現過這樣的邏輯,和/或是否有任何可用的代碼片段?

回答

7

Bloggart使用這種技術。看看this blog post

class StaticContentHandler(webapp.RequestHandler): 
    def output_content(self, content, serve=True): 
    self.response.headers['Content-Type'] = content.content_type 
    last_modified = content.last_modified.strftime(HTTP_DATE_FMT) 
    self.response.headers['Last-Modified'] = last_modified 
    self.response.headers['ETag'] = '"%s"' % (content.etag,) 
    if serve: 
     self.response.out.write(content.body) 
    else: 
     self.response.set_status(304) 

    def get(self, path): 
    content = get(path) 
    if not content: 
     self.error(404) 
     return 

    serve = True 
    if 'If-Modified-Since' in self.request.headers: 
     last_seen = datetime.datetime.strptime(
      self.request.headers['If-Modified-Since'], 
      HTTP_DATE_FMT) 
     if last_seen >= content.last_modified.replace(microsecond=0): 
     serve = False 
    if 'If-None-Match' in self.request.headers: 
     etags = [x.strip('" ') 
       for x in self.request.headers['If-None-Match'].split(',')] 
     if content.etag in etags: 
     serve = False 
    self.output_content(content, serve) 
+0

優秀的例子! ;) – 2010-05-01 20:58:19

+0

我已經根據這個例子實現了我的解決方案,並且一切正常。謝謝jbochi和Nick! – Emilien 2010-05-02 18:25:23

0

這裏可能有一個更簡單的解決方案。這要求你不要覆蓋與任何標識符相關的數據,例如修改圖像將創建一個新的ID(因此一個新的URL)。

只需將請求處理程序中的Expires標題設置爲遠程將來,例如,現在+一年。這將導致客戶端緩存映像,並且在該時間到來之前不會要求更新。

這種方法有一些權衡,如確保在修改圖像時嵌入新的URL,因此您必須自行決定。 jbochi提出的另一種選擇是將更多的邏輯放入圖像請求處理程序中。

+0

這確實是一個可能的解決方案。正如我所說,我不指望圖像改變,但你永遠不知道。我將考慮尼克的解決方案,因爲除了這些圖片之外,我還會有其他靜態內容,而這些內容可能會發生變化,因此擁有一種解決方案似乎是最好的解決方案。雖然謝謝! – Emilien 2010-05-02 08:54:06

0

順便說一下,感謝webob,webapp.RequestHandler提供了簡單的方法來檢查If-None-Match。

if etag in self.request.if_none_match: 
    pass # do something 
0

爲什麼代碼使用:

self.response.headers['ETag'] = '"%s"' % (content.etag,) 

,而不是這樣的:

self.response.headers['ETag'] = '"%s"' % content.etag 

我認爲這是相同的,除非有人解釋的理由將使用第二。

相關問題