django 条件视图处理--Conditional View Processing

条件视图处理

HTTP clients 可以发送许多的headers来告知服务器它们已经查看到的资源副本。这通常用在检索一个web 页面(使用GET请求方法)时避免服务器发送客户机已经检索到的所有数据。然而,相同的headers可以用于所有的HTTP请求方法(POST, PUT, DELETE等)。

Django 从视图view返回的每一个页面(response),可能会提供两个HTTP headers: ETag header 和 Last-Modified header. 这些headers 在HTTP的响应上是可选的。它们可以由你的视图函数来设置,或者你可以依赖 ConditionalGetMiddleware中间件来设置ETag header.

当客户机下一次请求相同的资源时,它可能会发送一个header,例如要么是If-modified-since要么是If-unmodified-since*,其中包含上次发送最后修改时间的日期,要么是If-match 要么是If-none-match,其中包含上次发送的ETag。如果页面的当前版本与客户端发送的ETag匹配,或者资源没有被修改,将返回一个304状态码,而不是完整的响应,以此告诉客户端内容没有任何改变。根据header, 如果页面被修改或与客户端发送ETag不匹配,一个412状态码(先决条件失败)将被返回。

当您需要更细粒度的控制时,可以使用为每个视图使用条件处理函数

condition 装饰器

有时(实际上,经常如此),您可以创建函数来快速计算资源的ETag值或最后修改时间,而不需要进行构建完整视图所需的所有计算。Django可以使用这些函数为视图处理提供“预警”选项。告诉客户端自上次请求以来,内容没有被修改。

这两个函数作为参数传递给django.views.decorator .http.condition 装饰器。这个装饰器使用两个函数(如果您不能轻松快速地计算两个数量,您只需要提供一个函数)来计算HTTP请求中的头是否与资源中的头匹配。如果它们不匹配,则必须计算的一个新的资源副本,然后调用您的正常视图。

condition 装饰器的使用样子看起来是像是这样的:

condition(etag_func=None, last_modified_func=None)

计算ETag和last modified time的两个函数将以相同的参数顺序传入到request对象里,它们将帮助封装视图函数。传入的last_modified_func函数返回一个标准的datetime值,指定最后一次修改资源的时间,如果资源没有文本,则返回None。传递给etag装饰器的函数返回表示资源ETag的字符串,如果不存在,则返回None。

如果视图还没有设置ETag和Last-Modified头,并且请求的方法是安全的(GET或HEAD),装饰器将在响应中设置ETag和Last-Modified头。

有效地使用这个特性最好用一个例子来解释。假设您有这对模型,它们表示一个简单的博客系统

import datetime
from django.db import models

class Blog(models.Model):
    ...

class Entry(models.Model):
    blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
    published = models.DateTimeField(default=datetime.datetime.now)

如果显示最新博客条目的首页仅在添加新博客条目时发生更改,则可以非常快速地计算最后修改的时间。您需要为与该博客相关的每个条目提供最新的发布日期。一种方法是:

def latest_entry(request, blog_id):
    return Entry.objects.filter(blog=blog_id).latest("published").published

然后,可以使用此函数为首页视图提供未更改页面的早期检测

from django.views.decorators.http import condition

@condition(last_modified_func=latest_entry)
def front_page(request, blog_id):
    ...

注意装饰器的顺序:
当condition()返回一个条件响应时,它下面的任何装饰器都将被跳过,不会应用于响应。因此,任何需要同时应用于常规视图响应和条件响应的装饰器都必须在conditon()上方。特别是vary_on_cookie()、*vary_on_headers()cache_control()*应该放在前面,因为RFC 7232要求它们设置的头出现在304响应上。

将装饰器与其他HTTP方法一起使用

条件装饰器不仅适用于GET和HEAD请求(在这种情况下,HEAD请求与GET相同)。它还可以用于检查POST、PUT和DELETE请求。在这些情况下,我们的想法不是返回“not modified”响应,而是告诉客户他们试图更改的资源在此期间已经更改。

例如,客户机和服务器之间的以下交换:

  1. 客户端请求 /foo/.
  2. 服务端响应的内容带有一个ETag的值为"abcd1234"
  3. 客户端发送一个HTTP PUT 请求 /foo/ 更新资源。这个请求同时也发送一个if-Match: “abcd1234” headers 指明想要更新的哪个版本的资源。
  4. 通过计算ETag,和处理一个GET请求一样(使用同一个函数),服务器检查对应的资源是否被更改过。如果资源已经更改,它将返回一个412状态码,这意味着“先决条件失败”。
  5. 客户端收到一个412状态码后,发送一个GET请求/foo/, 检索最新的资源版本,然后再去请求更新资源。

这个例子说明了一件很重要的事是在所有情况下用相同的函数计算ETag 和 last modification 的值。实际上,你确实应该用同一个函数,以确保每次返回的值是一样的。

非安全请求方法的验证头(Validator headers with non-safe request methods)
条件修饰器仅为安全的HTTP方法设置验证器头(ETag和last - modified),即GET和HEAD。如果您希望在其他情况下返回它们,请在您的视图中设置它们。查看RFC 7231#section-4.3.4了解在响应PUT和POST请求时设置验证头之间的区别.

与中间件条件处理进行比较

Django 提供了简浩django.middleware.http.ConditionalGetMiddleware中间件来实现GET请求的条件处理。虽然这用起来很容易,且适用于多数情况,这个中间件还有一些限制的:

  • 它是全局的,应用于你工程中的所有视图
  • 它不能避免生成响应,而生成响应的代价可能很高
  • 它只适用于HTTP GET请求

您应该针对特定问题选择最合适的工具。如果您有一种快速计算ETags和修改时间的方法,并且如果一些视图需要一段时间来生成内容,那么您应该考虑使用本文档中描述的condition 装饰器.如果一切都运行得相当快,坚持使用中间件,在视图没有改变的情况下,返回给客户机的网络通信量仍然会减少.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值