django中的缓存 跨域问题(同源策略)
django缓存机制 |
在动态网站中,用户所有的请求,服务器都会去数据库中进行相应的增,删,查,改,渲染模板,执行业务逻辑,最后生成用户看到的页面.
当一个网站的用户访问量很大的时候,每一次的的后台操作,都会消耗很多的服务端资源,所以必须使用缓存来减轻后端服务器的压力.
缓存是将一些常用的数据保存内存或者memcache中,在一定的时间内有人来访问这些数据时,则不再去执行数据库及渲染等操作,而是直接从内存或memcache的缓存中去取得数据,然后返回给用户.
django中的6中缓存方式
开发调试缓存 没有缓存
内存缓存
文件缓存
数据库缓存
缓存到redis
Memcache缓存(使用python-memcache模块)
Memcache缓存(使用pylibmc模块)
经常使用的有文件缓存和Mencache缓存
缓存配置
settings中配置缓存位置的配置(settings中配置,BACKEND不同,缓存的位置不同) 必须要配置
CACHES = { 'default':{ 'BACKEND':'django.core.cache.backends.filebased.FileBasedCache', #指定缓存使用的引擎 'LOCATION':'E:\huancun_redis', #指定缓存的路径 'TIMEOUT':300, #缓存超时时间(默认为300秒,None表示永不过期) 'OPTIONS':{ 'MAX_ENTRIES':300, #最大缓存记录的数量(默认300) 'CULL_FREQUENCY':3, #缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3) } } }
缓存粒度
全站缓存
单页面缓存
局部缓存
文件缓存(把缓存数据存储在文件中)
使用:
settings文件,把cache配置进去
单页面缓存:在视图函数上加一个装饰器
from django.views.decorators.cache import cache_page @cache_page(5) 5 代表缓存时间
例子
fbv加局部缓存装饰器
import time from django.views.decorators.cache import cache_page 局部缓存装饰器 # #局部缓存 @cache_page(5) def index(request): ctime = time.time() return render(request,'index.html',{'ctime':ctime})
cbv加装饰器
from django.utils.decorators import method_decorator
django的bug,不能直接对类进行装饰,必须使用 method_decorator,把装饰器当作参数传进去。
@method_decorator(wrapper, name="post")
#PS:CBV中添加装饰器 def wrapper(func): def inner(*args,**kwargs): return func(*args,**kwargs) return inner
#1.指定方法上添加装饰器 class Foo(View): @method_decorator(wrapper) def get(self,request): pass def post(self,request): pass
#2.在类上添加 @method_decorator(wrapper,name='dispatch') class Foo(View): def get(self,request): pass def post(self,request): pass
局部缓存
{% load cache %} {% cache 5 'test'} <!--第一个参数表示缓存时间,第二个参数是key值(取缓存的时候,需要根据key值取)--> 当前时间:{{ ctime }} {% endcache %}
视图函数
from django.views.decorators.cache import cache_page import time from .models import * def index(request): cttime=time.time() #获取当前时间 bookList=Book.objects.all() return render(request,"index.html",locals())
全站缓存
既然是全站缓存,当然要使用Django中的中间件.
用户的请求通过中间件,经过一系列的认证等操作,如果请求的内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户
当返回给用户之前,判断缓存中是否已经存在,如果不存在,则UpdateCacheMiddleware会将缓存保存至Django的缓存之中,以实现全站缓存
#缓存整个站点,是最简单的缓存方法 #在MIDDLEWARE_CLASSES 中加入 "update"和"fetch"中间件 MIDDLEWARE_CLASSES = ( ‘django.middleware.cache.UpdateCacheMiddleware’, #第一 'django.middleware.common.CommonMiddleware', ‘django.middleware.cache.FetchFromCacheMiddleware’, #最后 ) #"update"必须配置在第一个 #"fetch" 必须配置在最后一个
需要改settings.py配置文件
MIDDLEWARE = [ 'django.middleware.cache.UpdateCacheMiddleware', #全局控制 内部有process_response 响应HTTPResponse中设置几个headers 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.cache.FetchFromCacheMiddleware' #全局控制 内部有process_request 用来缓存通过GET和HEAD方法获取的状态码为200的响应 ] CACHE_MIDDLEWARE_SECONDS=5 #去局配置缓存 过期时间
视图函数
import time def index(request): ctime = time.time() return render(request,'index.html',{'time':ctime})
模板
{{ time }}
其余代码不变,刷新浏览器5秒,页面上的时间变化一次,这样就实现了全站缓存
高级用法
前后端分离项目
from django.core.cache import cache
cache.set cache.get
设置值跟取值:
cache.set('test_data',{'name':'lqz','age':18},5)
cache.get('test_data')
自定义Response对response再次进行封装
from rest_framework.response import Response class MyResponse(): def __init__(self): self.code = 100 self.msg = None def get_response(self): return Response(self.__dict__) #返回名称空间
使用
from app01.utils import MyResponse #自定义Response封装 from rest_framework.views import APIView class Test(APIView): def get(self,request): response = MyResponse() response.data = {'name':'llxbl','age':18} response.code = 200 response.msg = '查询成功' return response.get_response()
开发调试(此模式为开发调试使用,实例上不执行任何操作)
settings配置
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 缓存后台使用的引擎 'TIMEOUT': 300, # 缓存超时时间(默认300秒,None表示永不过期,0表示立即过期) 'OPTIONS':{ 'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300) 'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3) }, } }
第二种
# 此为开始调试用,实际内部不做任何操作 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 引擎 'TIMEOUT': 300, # 缓存超时时间(默认300,None表示永不过期,0表示立即过期) 'OPTIONS':{ 'MAX_ENTRIES': 300, # 最大缓存个数(默认300) 'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3) }, 'KEY_PREFIX': '', # 缓存key的前缀(默认空) 'VERSION': 1, # 缓存key的版本(默认1) 'KEY_FUNCTION': 函数名 # 生成key的函数(默认函数会生成为:【前缀:版本:key】) } } # 自定义key def default_key_func(key, key_prefix, version): """ Default function to generate keys. Constructs the key used by all other methods. By default it prepends the `key_prefix'. KEY_FUNCTION can be used to specify an alternate function with custom key making behavior. """ return '%s:%s:%s' % (key_prefix, version, key) def get_key_func(key_func): """ Function to decide which key function to use. Defaults to ``default_key_func``. """ if key_func is not None: if callable(key_func): return key_func else: return import_string(key_func) return default_key_func
内存缓存(将缓存内容保存至内存区域中)
settings配置
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', # 指定缓存使用的引擎 'LOCATION': 'unique-snowflake', # 写在内存中的变量的唯一值 'TIMEOUT':300, # 缓存超时时间(默认为300秒,None表示永不过期) 'OPTIONS':{ 'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300) 'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3) } } }
数据库缓存(把缓存数据存储在数据库中)
settings配置
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.db.DatabaseCache', # 指定缓存使用的引擎 'LOCATION': 'cache_table', # 数据库表 'OPTIONS':{ 'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300) 'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3) } } }
# 注创建缓存的数据库表使用的语句:执行创建表命令 python manage.py createcachetable
Memcache缓存(使用python-memcached模块连接memcache)
Memcached是Django原生支持的缓存系统.要使用Memcached,需要下载Memcached的支持库python-memcached或pylibmc.
settings.py文件配置
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', # 指定缓存使用的引擎 'LOCATION': '192.168.10.100:11211', # 指定Memcache缓存服务器的IP地址和端口 'OPTIONS':{ 'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300) 'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3) } } }
LOCATION也可以配置成如下:
'LOCATION': 'unix:/tmp/memcached.sock', # 指定局域网内的主机名加socket套接字为Memcache缓存服务器 'LOCATION': [ # 指定一台或多台其他主机ip地址加端口为Memcache缓存服务器 '192.168.10.100:11211', '192.168.10.101:11211', '192.168.10.102:11211', ]
第二种
# 此缓存使用python-memcached模块连接memcache CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': '127.0.0.1:11211', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': 'unix:/tmp/memcached.sock', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': [ '172.19.26.240:11211', '172.19.26.242:11211', # 设置权重,memcache模块做的 ('172.19.26.240:11211',1) ('172.19.26.242:11211',10) ] } }
Memcache缓存(使用pylibmc模块连接Memcache)
settings.py文件配置 CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', # 指定缓存使用的引擎 'LOCATION':'192.168.10.100:11211', # 指定本机的11211端口为Memcache缓存服务器 'OPTIONS':{ 'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300) 'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3) }, } }
LOCATION也可以配置成如下:
'LOCATION': '/tmp/memcached.sock', # 指定某个路径为缓存目录 'LOCATION': [ # 分布式缓存,在多台服务器上运行Memcached进程,程序会把多台服务器当作一个单独的缓存,而不会在每台服务器上复制缓存值 '192.168.10.100:11211', '192.168.10.101:11211', '192.168.10.102:11211', ]
Memcached是基于内存的缓存,数据存储在内存中.所以如果服务器死机的话,数据就会丢失,所以Memcached一般与其他缓存配合使用
第二种
# 此缓存使用pylibmc模块连接memcache CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': '127.0.0.1:11211', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': '/tmp/memcached.sock', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': [ '172.19.26.240:11211', '172.19.26.242:11211', ] } }
跨域问题(同源策略) |
浏览器的:同源策略,浏览器拒绝不是当前域返回的数据
ip地址和端口号都相同才是同一个域
比如:我在本地上的域名是127.0.0.1:8000,请求另外一个域名:127.0.0.1:8001一段数据
浏览器上就会报错,个就是同源策略的保护,如果浏览器对javascript没有同源策略的保护,那么一些重要的机密网站将会很危险
已拦截跨源请求:同源策略禁止读取位于 http://127.0.0.1:8001/SendAjax/ 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。
但是注意,项目2中的访问已经发生了,说明是浏览器对非同源请求返回的结果做了拦截
如何解决:
CORS:跨域资源共享
简单请求:发一次请求
非简单请求:非简单请求是发送了两次请求,第一次是预检请求(OPTIONS请求),当预检通过,允许我发请求,再发送真实的请求
简单请求需要满足两大条件
(1) 请求方法是以下三种方法之一: HEAD GET POST (2)HTTP的头信息不超出以下几种字段: Accept Accept-Language Content-Language Last-Event-ID Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不同时满足上面两个条件,就属于非简单请求。
浏览器对这两种请求的处理,是不一样的。
* 简单请求和非简单请求的区别? 简单请求:一次请求 非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。 * 关于“预检” - 请求方式:OPTIONS - “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息 - 如何“预检” => 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过 Access-Control-Request-Method => 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过 Access-Control-Request-Headers
支持跨域,简单请求
服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'
支持跨域,复杂请求
由于复杂请求时,首先会发送“预检”请求,如果“预检”成功,则发送真实数据。
- “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
- “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
$('button').click(function () {
alert('111');
$.ajax({
url:'http://127.0.0.1:8001/index/',
type:'post',
contentType:'application/json',
data:{'name':'lqz'},
success:function (data) {
console.log(data)
}
})
})
被请求站点
def index(request): obj = HttpResponse('11111111') if request.method == 'OPTIONS': # #允许它 obj['Access-Control-Allow-Headers']='Content-Type' # # obj['Access-Control-Allow-Headers'] = '*' # # # # obj['Access-Control-Allow-Origin'] = '*' obj['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' print(obj) return obj
解决跨域问题:(写好一个中间件配置一下) 被请求站点
from django.utils.deprecation import MiddlewareMixin class MyCorsMiddle(MiddlewareMixin): def process_response(self, request, response): if request.method == 'OPTIONS': #允许它 response['Access-Control-Allow-Headers'] = 'Content-type' #response['Access-Control-Allow-Headers'] = '*' # response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' # 允许的请求站点 response['Access-Control-Allow-Origin'] = '*' return response
MIDDLEWARE = [ 'app01.MyMiddle.MyCorsMiddle', #跨域问题 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]