Django条件视图处理装饰器添加陈旧的Etag

时间:2017-04-19 11:58:38

标签: django http-headers etag

我一直在尝试使用Django条件视图处理功能。基本上我想拒绝一个实体的更新操作,如果它已被其他用户修改过,而且这似乎适用于Django提供的@ condition装饰器。

然而,在测试它时我注意到了一个问题,后来我检查了Django源代码,我发现了我认为可能是一个bug,但只是想在向Django提交错误报告并修复之前先确认一下

当一个新请求进入时会调用装饰器,它首先根据传递给装饰器的函数计算ETag和Last Modified时间戳,然后将控制传递给get_conditional_response()函数。这里将执行ETag和Last Modified验证,如果它们与请求中提供的内容不匹配,则请求将被拒绝。到目前为止一切都很好。

如果检查通过,则允许请求并调用视图以处理请求并生成响应。在处理请求时,如果它是不安全的方法,例如PUTPATCH,它会更新实体,这很可能会更改ETag和Last Modified值。

但是,我注意到,在实际执行更新之前,通过ETag或上次修改时间戳计算出<{1}}或PUT的成功响应,并通过现在这些值无效或陈旧。这对我来说似乎是错的。在同一实体上执行新的PATCH,然后在响应中为用户提供更新的ETag和Last Modified值。

你不认为,GET装饰者应该检查请求方法是否不安全,然后它应该在视图处理后重新计算ETag和Last Modified,然后将新值添加到响应?

2 个答案:

答案 0 :(得分:2)

我同意这里有一个错误,但我认为它与你所描述的有些不同。

条件请求在RFC 7232中定义,但遗憾的是,该文档并未明确说明何时应在响应中使用条件标头。它does say

  

<强> 2.4。何时使用实体标签和最后修改日期

     

在对GET或HEAD的200(OK)响应中,原始服务器......

这可能导致人们假设在其他响应中未定义标头的使用。

但是,RFC 7231明确允许在对PUT的响应中使用ETag,匹配新表示(就像你的直觉一样)。但请注意this caveat

  

原始服务器不得在成功响应PUT时发送验证器头字段(第7.2节),例如ETag或Last-Modified字段,除非保存请求的表示数据而未应用任何转换身体......

也就是说,客户端将使用ETag的存在或不存在来确定其表示(它仅作为正文发送到PUT)是否是实际存储的表示。 (有关此点的更多详细信息,请参阅this question。)

然而,Django的条件请求API不允许进行这种区分。具体地说,用户无法指示视图是否在没有“转换应用于主体”的情况下保存了表示。因此,condition()装饰器无法知道是否有必要添加ETag。

所以唯一要做的就是保守,在这种情况下根本不返回条件头。随意创建一张票(或者我可以做到)。

答案 1 :(得分:0)

创建自定义中间件以在GET / HEAD请求中处理etag。 以下代码( Django 1.10 )显示了如何使用中间件创建和处理etag。

注意:不要在设置文件中启用USE_ETAGS

process_response(self, request, response)

我正在使用Django 1.10。如果您使用的是较低版本,则使用__call__方法中实现的逻辑覆盖MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', # myapp contains middleware.py file and # ETag class is implemented inside the middleware.py file 'myapp.middleware.Etag', ] 方法。并且不要忘记将其添加到设置文件中的MIDDLEWARE / MIDDLEWARE_CLASSES

myData = myData.withColumn('area', regexp_replace('area', ',', '.').cast('float'))