Send a “304 Not Modified” for images stored in the datastore

前端 未结 4 2067
迷失自我
迷失自我 2021-02-04 20:43

I store user-uploaded images in the Google App Engine datastore as db.Blob, as proposed in the docs. I then serve those images on /images/.jpg

相关标签:
4条回答
  • 2021-02-04 20:56

    why would the code use this:

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

    instead of this:

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

    I think it is the same and will use the 2nd unless someone explains the reasoning.

    0 讨论(0)
  • 2021-02-04 21:04

    By the way, thanks to webob, webapp.RequestHandler provides easy way to check If-None-Match.

    if etag in self.request.if_none_match:
        pass # do something
    
    0 讨论(0)
  • 2021-02-04 21:09

    There might be a simpler solution here. This requires that you never overwrite the data associated with any identifier, e.g. modifying the image would create a new id (and hence a new URL).

    Simply set the Expires header from your request handler to the far future, e.g. now + a year. This would result in clients caching the image and not asking for an update until that time comes.

    This approach has some tradeoffs, like ensuring new URLs are embedded when images are modified, so you have to decide for yourself. What jbochi is proposing is the other alternative that puts more logic into the image request handler.

    0 讨论(0)
  • 2021-02-04 21:10

    Bloggart uses this technique. Have a look at 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 讨论(0)
提交回复
热议问题