16:django 有条件的视图处理(Last-Modified和ETag)&&加密签名

有条件的视图处理

上一节我们介绍了缓存来减轻服务器的负担,这里的有条件的视图处理也从一定程度上减轻了服务器的负担,在正式介绍之前,先来看两个概念:Last-Modified和ETag

Last-Modified

在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是客户端请求的资源,同时有一个Last-Modified的属性标记此文件在服务期端最后被修改的时间,格式类似这样:

Last-Modified : Fri , 12 May 2006 18:53:33 GMT

客户端第二次请求此URL时,根据HTTP协议的规定,浏览器会向服务器传送If-Modified-Since报头,询问该时间之后文件是否有被修改过:

If-Modified-Since : Fri , 12 May 2006 18:53:33 GMT

如果服务器端的资源没有变化,则自动返回 HTTP 304(Not Changed.)状态码,内容为空,这样就节省了传输数据量。当服务器端代码发生改变或者重启服务器时,则重新发出资源,返回和第一次请求时类似。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。

ETag

请求流程

Etag由服务器端生成,客户端通过If-Match或者说If-None-Match这个条件判断请求来验证资源是否修改。常见的是使用If-None-Match.请求一个文件的流程可能如下:

====第一次请求===

1.客户端发起 HTTP GET 请求一个文件;

2.服务器处理请求,返回文件内容和一堆Header,当然包括Etag(例如"2e681a-6-5d044840")(假设服务器支持Etag生成和已经开启了Etag).状态码200

====第二次请求===

1.客户端发起 HTTP GET 请求一个文件,注意这个时候客户端同时发送一个If-None-Match头,这个头的内容就是第一次请求时服务器返回的Etag:2e681a-6-5d044840

2.服务器判断发送过来的Etag和计算出来的Etag匹配,因此If-None-Match为False,不返回200,返回304,客户端继续使用本地缓存;

流程很简单,问题是,如果服务器又设置了Cache-Control:max-age和Expires呢,怎么办?

答案是同时使用,也就是说在完全匹配If-Modified-Since和If-None-Match即检查完修改时间和Etag之后,服务器才能返回304.(不要陷入到底使用谁的问题怪圈)

作用

Etag 主要为了解决 Last-Modified 无法解决的一些问题。

1、一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;

2、某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒)

3、某些服务器不能精确的得到文件的最后修改时间;

为此,HTTP/1.1引入了 Etag(Entity Tags).Etag仅仅是一个和文件相关的标记,可以是一个版本标记,比如说v1.0.0或者说"2e681a-6-5d044840"这么一串看起来很神秘的编码。但是HTTP/1.1标准并没有规定Etag的内容是什么或者说要怎么实现,唯一规定的是Etag需要放在""内。

知道了这两个概念之后,我们应该知道这两个概念的作用了吧,也大概知道我们接下来要讲解的是什么啦。没错,就是,django中如何使用Last-Modified和ETag这两个概念呢

condition装饰器

Last-Modified和ETag在django中是两个函数,前者返回一个日期类型数据,后者返回一个值(ETag值),这两个函数可以作为参数传递给django.views.decorators.http.condition这个装饰器,装饰器原型是

condition(etag_func=None, last_modified_func=None)

这是一个使用的简单例子

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):
    ...

在django.views.decorators.http.condition文件里还提供了另外两个装饰器,可以使得只需要提供一个参数即可,看源码很容易懂:

def etag(etag_func):
    return condition(etag_func=etag_func)

def last_modified(last_modified_func):
    return condition(last_modified_func=last_modified_func)

说完了Last-Modified和ETag,我们继续说一下

django加密签名

web应用安全的黄金法则是:永远不要相信从不受信任来源的数据。但有时候我们只能从不受信任的媒介获取或者发送数据,或者不受信任的媒介更具吸引力,比如我们确保我们的数据一定是安全的,并且不受信任的媒介比受信任媒介要快捷甚至便宜的多。加密签名的值一旦被篡改就会被检测到,这是我们能确保数据安全的共识。下面是几个加密签名应用的例子:

  • 找回密码所用的url
  • 确保form表单中的隐藏域没有被修改
  • 一次性的允许访问保护数据的加密url

django提供了一个底层的用来加密数据的API和一个高层的用来设置和读取加密cookies的API

保护好你的SECRET_KEY

用django-admin.py startproject命令生成的项目自带一个自动随机生成的SECRET_KEY,注意不要泄露这个key

使用低层次的API

django的加密方法源代码位于django\core目录下的signing.py文件,可以具体去看看,下面是一些基本的用法:

>>> from django.conf import settings
>>> settings.configure()
>>> from django.core.signing import Signer
>>> signer = Signer()
>>> value = signer.sign("qiweijie")
>>> value
‘qiweijie:lVrPb11e1K9K_DcxnMGNYk8t2aQ‘
>>> original = signer.unsign(value)
>>> original
u‘qiweijie‘

使用“调味剂”参数(salt)

salt是“盐,调味剂”的意思,如果你不想每次对同一字符加密的结果都一样,那么你可以是用调味剂参数调剂一下,哈哈,看示例:

>>> signer = Signer()
>>> signer.sign(‘My string‘)
‘My string:GdMGD6HNQ_qdgxYP8yBZAdAIV1w‘
>>> signer = Signer(salt=‘extra‘)
>>> signer.sign(‘My string‘)
‘My string:Ee7vGi-ING6n02gkcJ-QLHg6vFw‘
>>> signer.unsign(‘My string:Ee7vGi-ING6n02gkcJ-QLHg6vFw‘)
u‘My string‘

验证时间戳

TimestampSigner是Signer的子类,添加了一个加密的时间戳给值。这允许你可以确保一个加密的数据是在一个给定的时间内创建的

>>> from django.core.signing import TimestampSigner
>>> signer = TimestampSigner()
>>> value = signer.sign(‘hello‘)
>>> value
‘hello:1NMg5H:oPVuCqlJWmChm1rA2lyTUtelC-c‘
>>> signer.unsign(value)
u‘hello‘
>>> signer.unsign(value, max_age=10)
...
SignatureExpired: Signature age 15.5289158821 > 10 seconds
>>> signer.unsign(value, max_age=20)
u‘hello‘

保护复杂的数据结构

列表,元组和字典,如果你直接使用上述的方法,最后得到的是一个字符串而不是原来的数据类型:

>>> dic = {1:2}
>>> sd=signer.sign(dic)
>>> signer.unsign(sd)
u‘{1: 2}‘

如果你想保护这些数据类型,请使用dumps和loads方法,它们都位于django.core.signing模块里面

dumps(objkey=Nonesalt=‘django.core.signing‘compress=False)
loads(stringkey=Nonesalt=‘django.core.signing‘max_age=None)
>>> from django.core import signing
>>> value = signing.dumps({"foo": "bar"})
>>> value
‘eyJmb28iOiJiYXIifQ:1NMg1b:zGcDE4-TCkaeGzLeW9UQwZesciI‘
>>> signing.loads(value)
{‘foo‘: ‘bar‘}
时间: 2024-08-15 05:48:10

16:django 有条件的视图处理(Last-Modified和ETag)&&加密签名的相关文章

django book学习笔记——视图和URL配置

1.视图 一个视图就是Python的一个函数,每个视图函数至少要有一个参数,通常被叫作request. 这是一个触发这个视图.包含当前Web请求信息的对象,是类django.http.HttpRequest的一个实例.它返回一个HttpResponse实例.为了使一个Python的函数成为一个Django可识别的视图,它必须满足这两个条件.(也有例外) 例: from django.http import HttpResponse def hello(request):         retu

解读ASP.NET 5 & MVC6系列(16):自定义View视图文件查找逻辑

原文:解读ASP.NET 5 & MVC6系列(16):自定义View视图文件查找逻辑 之前MVC5和之前的版本中,我们要想对View文件的路径进行控制的话,则必须要对IViewEngine接口的FindPartialView或FindView方法进行重写,所有的视图引擎都继承于该IViewEngine接口,比如默认的RazorViewEngine.但新版本MVC6中,对视图文件的路径方式却不太一样了,目前有两种方式,一种是通过RazorViewEngine,另外一种是通过新特性IViewLoc

[Django]中建立数据库视图

Django中建立数据库视图 Django中没有建立视图的接口,如果要建立一个视图需要一些手动的改变. 这里使用的Django 版本>1.5, 使用的数据库为mysql 第一步 建立视图,例如视图的名称叫做 user_info 第二步 model中这么写: class MyModel(models.Model): ... class Meta: managed = False db_table = "user_info" 这样就可以把视图经过orm变成对象了. REF: crea

Django之View(视图)

一.Django的View(视图) 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应.用来处理业务逻辑. 响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. 无论视图本身包含什么逻辑,都要返回响应.代码写在哪里也无所谓,只要它在你当前项目目录下面.除此之外没有更多的要求了——可以说“没有什么神奇的地方”.为了将代码放在某处,大家约定成俗将视图放置在项目(project)或应用程序(app)目录中的名为

Django - - 基础 - - Django的View(视图)

目录 Django的View(视图) 一个简单的视图 CBV和FBV 给视图加装饰器 Request对象和Response对象 request对象 Response对象 JsonResponse对象 Django shortcut functions 1, Django的View(视图) 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. 无论视图本

Django基础三之视图函数

Django基础三之视图函数 本节目录 一 Django的视图函数view 二 CBV和FBV 三 使用Mixin 四 给视图加装饰器 五 Request对象 六 Response对象 一 Django的视图函数view 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. 无论视图本身包含什么逻辑,都要返回响应.代码写在哪里也无所谓,只要它在你当前项

Django 的View(视图)系统

Django的View(视图) 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. 无论视图本身包含什么逻辑,都要返回响应.代码写在哪里也无所谓,只要它在你当前项目目录下面.除此之外没有更多的要求了——可以说“没有什么神奇的地方”.为了将代码放在某处,大家约定成俗将视图放置在项目(project)或应用程序(app)目录中的名为views.py的文件

(django)11类视图

目录 1. 使用类视图 创建类视图 注册路由 类视图使用装饰器 在url中装饰 在类视图中装饰 method_decorator 的 name 参数 使用Mixin扩展类 使用函数方式定义的视图叫函数视图,虽然使用方便,便于理解,但是当一个s视图有多种请求方式的时候,变需要使用分支来编写不同请求方式对应的逻辑. 使用函数视图,代码看上去是这样子的 def my_view(request): if request.method == 'GET': return HttpResponse("get&

16 django用户认证组件

django用户认证组件 思考: 前一篇提到的seesion,当用户登录后会保存session. 浏览器再次访问会带上服务器返回的session:sessionid ---> 登录时随机生成的key 服务器拿到sessionid后去数据库匹配,匹配到后拿到一个字典数据:{a:b,c:d} 当数据有变化时,会更新某个值,如 c:d --> c:e ,那么直接更新数据库 {a:b,c:e},sessionid并不会变化,然后将原来的sessionid继续回传给浏览器. 这样的处理机制存在什么样的问