我一直在尝试使用Django条件视图处理功能。基本上我想拒绝一个实体的更新操作,如果它已被其他用户修改过,而且这似乎适用于Django提供的@ condition装饰器。
然而,在测试它时我注意到了一个问题,后来我检查了Django源代码,我发现了我认为可能是一个bug,但只是想在向Django提交错误报告并修复之前先确认一下
当一个新请求进入时会调用装饰器,它首先根据传递给装饰器的函数计算ETag和Last Modified时间戳,然后将控制传递给get_conditional_response()
函数。这里将执行ETag和Last Modified验证,如果它们与请求中提供的内容不匹配,则请求将被拒绝。到目前为止一切都很好。
如果检查通过,则允许请求并调用视图以处理请求并生成响应。在处理请求时,如果它是不安全的方法,例如PUT
或PATCH
,它会更新实体,这很可能会更改ETag和Last Modified值。
但是,我注意到,在实际执行更新之前,通过ETag或上次修改时间戳计算出<{1}}或PUT
的成功响应,并通过现在这些值无效或陈旧。这对我来说似乎是错的。在同一实体上执行新的PATCH
,然后在响应中为用户提供更新的ETag和Last Modified值。
你不认为,GET
装饰者应该检查请求方法是否不安全,然后它应该在视图处理后重新计算ETag和Last Modified,然后将新值添加到响应?
答案 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'))