发送“304 Not Modified”对于存储在数据存储中的图像

发布于 2024-08-30 15:18:02 字数 873 浏览 8 评论 0原文

我按照 文档。然后,我在 /images/.jpg 上提供这些图像。

服务器总是发送 200 OK 响应,这意味着浏览器必须多次下载相同的图像(==更慢)并且服务器必须多次发送相同的图像(==更多昂贵的)。

由于大多数图像可能永远不会改变,我希望能够发送 304 Not Modified 响应。 正在考虑在用户上传图片时计算图片的某种哈希值,然后用它来知道用户是否已经拥有该图像(也许将哈希值作为 Etag 发送?)

我 找到这个答案< /a> 和 这个答案很好地解释了逻辑,但我有两个问题:

  1. 是否可以在 Google App Engine 中发送 Etag
  2. 有没有人实现了这样的逻辑,和/或是否有可用的代码片段?

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/<id>.jpg.

The server always sends a 200 OK response, which means that the browser has to download the same image multiple time (== slower) and that the server has to send the same image multiple times (== more expensive).

As most of those images will likely never change, I'd like to be able to send a 304 Not Modified response. I am thinking about calculating some kind of hash of the picture when the user uploads it, and then use this to know if the user already has this image (maybe send the hash as an Etag?)

I have found this answer and this answer that explain the logic pretty well, but I have 2 questions:

  1. Is it possible to send an Etag in Google App Engine?
  2. Has anyone implemented such logic, and/or is there any code snippet available?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

囚你心 2024-09-06 15:18:02

Bloggart 使用这种技术。请查看这篇博文。

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)

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)
少钕鈤記 2024-09-06 15:18:02

这里可能有一个更简单的解决方案。这要求您永远不要覆盖与任何标识符关联的数据,例如修改图像将创建一个新的 id(从而创建一个新的 URL)。

只需将请求处理程序中的 Expires 标头设置为遥远的未来,例如现在+一年。这将导致客户端缓存图像并且直到那时才请求更新。

这种方法有一些权衡,例如确保修改图像时嵌入新的 URL,因此您必须自己决定。 jbochi 提出的是另一种替代方案,将更多逻辑放入图像请求处理程序中。

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.

热鲨 2024-09-06 15:18:02

顺便说一句,感谢 webob,webapp.RequestHandler 提供了简单的方法来检查 If-None-Match。

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

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
久伴你 2024-09-06 15:18:02

为什么代码会使用这个:

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

而不是这个:

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

我认为它是相同的,并且将使用第二个,除非有人解释原因。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文