我将用户上传的图片以db.Blob
格式存储在Google App Engine数据存储区中,如the docs中所述。然后我在/images/<id>.jpg
上提供这些图片。
服务器始终发送200 OK
响应,这意味着浏览器必须多次下载相同的图像(==较慢)并且服务器必须多次发送相同的图像(==更昂贵)。
由于大多数图片可能永远不会改变,我希望能够发送304 Not Modified
回复。我正在考虑在用户上传时计算图片的某种哈希值,然后使用它来了解用户是否已经拥有此图像(可能将哈希值发送为Etag
?)
我发现this answer和this answer可以很好地解释逻辑,但我有两个问题:
Etag
?答案 0 :(得分:8)
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)
答案 1 :(得分:0)
这里可能有一个更简单的解决方案。这要求您永远不会覆盖与任何标识符相关联的数据,例如修改图像会创建一个新的id(因此也是一个新的URL)。
只需将请求处理程序中的Expires
标头设置为远期,例如现在+一年。这将导致客户端缓存图像,直到那时才要求更新。
这种方法有一些权衡,例如在修改图像时确保嵌入新URL,因此您必须自己决定。 jbochi提出的另一种选择是将更多逻辑放入图像请求处理程序中。
答案 2 :(得分:0)
顺便说一下,感谢webob,webapp.RequestHandler提供了检查If-None-Match的简便方法。
if etag in self.request.if_none_match:
pass # do something
答案 3 :(得分:0)
为什么代码会使用这个:
self.response.headers['ETag'] = '"%s"' % (content.etag,)
而不是:
self.response.headers['ETag'] = '"%s"' % content.etag
我认为它是相同的,除非有人解释推理,否则将使用第二个。