2010-05-01 2 views
5

Ich speichere vom Benutzer hochgeladene Bilder im Google App Engine-Datenspeicher als db.Blob, wie in the docs vorgeschlagen. Ich serviere diese Bilder dann auf /images/<id>.jpg.Senden Sie eine "304 Not Modified" für Bilder, die im Datenspeicher gespeichert sind

Der Server sendet immer eine 200 OK Antwort, was bedeutet, dass der Browser das gleiche Bild mehrmals herunterladen muss (== langsamer) und dass der Server das gleiche Bild mehrmals senden muss (== teurer).

Da die meisten dieser Bilder wahrscheinlich nie ändern werden, würde ich gerne eine 304 Not Modified Antwort senden können. Ich denke an eine Art von Hash des Bildes berechnet wird, wenn die Börse es, und diese dann wissen, verwendet werden, wenn der Benutzer bereits dieses Bild hat (vielleicht den Hash als Etag schicken?)

Ich habe festgestellt this answer und this answer, die die Logik ziemlich gut, aber ich habe 2 Fragen erklären:

  1. Ist es möglich, ein Etag in Google App Engine zu senden?
  2. Hat jemand eine solche Logik implementiert und/oder ist ein Code-Snippet verfügbar?

Antwort

7

Bloggart verwendet diese Technik. Schauen Sie sich this blog post an.

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

Ausgezeichnetes Beispiel! ;) –

+0

Ich habe meine Lösung basierend auf diesem Beispiel implementiert, und alles funktioniert gut. Danke jbochi und Nick! – Emilien

0

Hier könnte es eine einfachere Lösung geben. Dies erfordert, dass Sie niemals die Daten überschreiben, die mit irgendeinem Identifizierer assoziiert sind, z. Durch das Ändern des Bildes wird eine neue ID (und damit eine neue URL) erstellt.

Setzen Sie einfach den Header Expires von Ihrem Anforderungshandler in die ferne Zukunft, z. jetzt + ein Jahr. Dies würde dazu führen, dass Clients das Image zwischenspeichern und erst zu diesem Zeitpunkt nach einem Update fragen.

Dieser Ansatz hat einige Kompromisse, wie zum Beispiel sicherstellen, dass neue URLs eingebettet werden, wenn Bilder geändert werden, so dass Sie für sich selbst entscheiden müssen. Was jbochi vorschlägt, ist die andere Alternative, die dem Bildanforderungs-Handler mehr Logik hinzufügt.

+0

Dies wäre in der Tat eine mögliche Lösung. Wie gesagt, ich erwarte nicht, dass sich die Bilder verändern, aber man weiß es nie. Ich werde mich mit Nicks Lösung befassen, da ich andere statische Inhalte als diese Bilder haben würde, und diese könnten sich ändern, also scheint es für mich die beste zu sein, eine Lösung für alle zu haben. Trotzdem danke! – Emilien

0

Übrigens bietet webapp.RequestHandler, dank webob, eine einfache Möglichkeit, If-None-Match zu überprüfen.

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

warum sollte der Code verwendet diese:

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

statt dem:

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

Ich denke, dass es das gleiche ist und die zweite verwenden, wenn jemand die Argumentation erklärt.

Verwandte Themen