【问题标题】:How to modify web2py download function to return "304 Not Modified" in case the file did not change?如果文件没有改变,如何修改web2py下载函数返回“304 Not Modified”?
【发布时间】:2013-01-25 04:22:29
【问题描述】:

就我而言,我有一个数据库,其中包含显示在概览页面上的文档缩略图。每次浏览器访问该站点时,都会再次下载所有缩略图,因此下载功能会再次加载数据库中的所有图像。由于我在 GAE 上运行,这会增加我的数据库读取量。

我尝试通过设置启用客户端站点缓存:

@auth.requires_login()
def download():
  response.headers['Cache-Control'] = None
  response.headers['Pragma'] = None
  response.headers['Expires'] = None
  return response.download(request, db)

我还读到 response.stream 可能会有所帮助,但 web2py 书说:

如上所述,response.download 应该用于检索通过上传字段存储的文件。 response.stream 可以用于其他情况,比如返回一个临时文件或者控制器创建的StringIO对象。

-- 编辑--

我启用了客户端缓存:

session.forget() #important
expire_time = datetime.timedelta(days=2)

response.headers['Cache-Control'] = 'private, max-age%d'%(60*60*24*2)
response.headers['Pragma'] = None
response.headers['Expires'] = (request.utcnow + expire_time).strftime("%a, %d %b %Y %H:%M:%S GMT")
response.headers['Content-Disposition'] = \
      'attachment;filename=' + filename + ';'

return response.stream(stream, filename=filename)

【问题讨论】:

    标签: python google-app-engine web2py


    【解决方案1】:

    首先,如果图像是公开可用的并且不需要验证即可查看,那么您可以将它们存储在 /static 文件夹中,然后将它们作为静态文件提供,而不是将它们存储在 /uploads 文件夹中。在这种情况下,将自动为客户端缓存设置标头(它也将更快、更高效)。

    其次,您可以使用response.stream() 流式传输上传的文件,但它不会自动识别文件所在的文件夹,也不会从编码的文件名中解码原始文件名并将其添加到 Content-Disposition 标头(即在这种情况下您无论如何都不需要,因为您正在显示图像而不是下载它们)。所以,只要你将完整的文件路径传递给response.stream(),你应该可以在这种情况下使用它,并且它会为缓存设置适当的响应头。

    最后,如果你想直接设置响应头,应该是这样的:

    import os
    import time
    modified = os.stat(file)[stat.ST_MTIME]
    mtime = time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(modified))
    response.headers['Last-Modified'] = mtime
    response.headers['Pragma'] = 'cache'
    response.headers['Cache-Control'] = 'private'
    

    【讨论】:

    • 我无法将图像直接存储在静态图像中,因为: 1. 应用程序在 Google App Engine 上运行。 2.文件需要认证。我会试试你的第二个提案的运气
    • 我试过了:response.headers['Content-Type'] = 'image/jpeg'response.headers['Pragma'] = 'cache'response.headers['Cache-Control'] = 'private'return response.stream(stream, filename=filename) 但服务器没有响应 304,我错过了什么?
    • 对不起,忘了你提到你在 GAE 上。您是否也设置了 Last-Modified 标头?
    • 好的,我首先意识到我必须使用session.forget()。否则(gae 或 web2py?)将由于存在 Set-Cookie 标头而将 Expire 标头设置为当前时间。这是因为某些代理存在安全问题。related issue Ticket。是的,我之前还设置了 Last-Modified 标头。当我开始工作时,我会发布更多细节
    • 我查看了 response.stream 的来源,对我来说,stream_file_or_304_or_206 似乎只有当流是 str -> 文件系统上的文件时才会执行。这在某种程度上是有道理的,因为否则系统在上次修改文件时没有任何信息。一种解决方法是在表中添加一个 add 'last-modified' 字段并在调用 response.stream 之前手动检查它,如果 last-modified 等于数据库值,则引发 304 异常。但是因为这也需要数据库查询,所以它不能解决我的问题。我会更新你对我的工作解决方案的回答
    【解决方案2】:

    如果您提供图片,为什么不使用 Google 高性能图片服务。使用此 API (get_serving_url),Google 将为您提供图像。您不需要处理程序!它速度很快,您可以调整大小,而且只需要一些带宽。

    但这仅适用于图像。这是我的一些代码,用于从 blobstore 提供 CSS,包括 304。

    class DynCSS(blobstore_handlers.BlobstoreDownloadHandler):
    
        def get(self, resource):                                        
    
            (key, _, _) = resource.rpartition('.')
            self.response.headers[str('ETag')] = str(key)
            if 'If-None-Match' in self.request.headers:
                etags = [x.strip()
                         for x in self.request.headers[str('If-None-Match')].split(',')]
                if key in etags:
                    self.response.set_status(304) # optimize traffic 304
                    return
            blob_info = blobstore.BlobInfo.get(key) 
            self.send_blob(blob_info, save_as=True)
    

    资源参数是一个添加了 .css 的 blob_key。我使用 unicode 文字。

    高性能图像服务使用:get_serving_url https://developers.google.com/appengine/docs/python/images/functions

    例子:

    entity.serving_url = images.get_serving_url(entity.blob_key, size=None, secure_url=True)
    

    如何使用:

    • 将您的图片上传到您的 blobstore
    • 将带有图像文件名的 blob_key 保存在数据存储区中
    • 创建一个 get_serving_url。您只需创建一次。
    • 在您的模板 img 标签中使用服务网址。

    serving_url 如下所示:https://lh6.ggpht.com/lOghqU2JrYk8M-Aoio8WjMM6mstgZcTP0VzJk79HteVLhnwZy0kqbgVGQZYP8YsoqVNzsu0EBysX16qMJe7H2BsOAr4j=s70

    【讨论】:

    • 您能否提供指向 Google 高性能图像 API 文档的链接?
    猜你喜欢
    • 2011-02-28
    • 1970-01-01
    • 2013-12-22
    • 2012-08-28
    • 1970-01-01
    • 2022-01-11
    • 2014-01-25
    • 2023-02-12
    • 2014-07-22
    相关资源
    最近更新 更多