限速缓存

django缓存配置

  • 首先在setting中配置CACHES,默认的是使用django本机内存作为网站
    1
    2
    3
    4
    5
    6
    7
    'django.core.cache.backends.db.DatabaseCache'
    'django.core.cache.backends.dummy.DummyCache'
    'django.core.cache.backends.filebased.FileBasedCache'
    'django.core.cache.backends.locmem.LocMemCache'
    'django.core.cache.backends.memcached.MemcachedCache'
    'django.core.cache.backends.memcached.PyLibMCCache'
    'django_redis.cache.RedisCache' # 需下载django_redis

redis缓存配置

1
2
3
4
5
6
7
8
9
10
11
# pip install django-redis
# settings.py
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://ip:port/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}

9全局配置调用

  • 即使用缓存中间件全局配置
    1
    2
    3
    4
    5
    MIDDLEWARE = [
    ...
    'django.middleware.cache.CacheMiddleware'
    ...
    ]

函数视图缓存

1
2
3
4
5
6
7
8
9
10
11
from django.views.decorators.cache import cache_page

@cache_page(60 * 15, key_prefix="site")
def my_view(request):

from django.views.decorators.cache import cache_page
urlpatterns = [
url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
#也可以这样,如果你的视图是classbase的话:
url(r'^$', cache_page(60 * 60 * 10, key_prefix="blogindex")(views.IndexView.as_view()), name='index'),
]

类视图缓存

1
2
3
4
5
6
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from django.views.generic import ListView

@method_decorator(cache_page(60*60), name='dispatch')
class MyListView(ListView):

drf缓存

1
2
3
4
5
6
7
8
9
10
11
pip install drf-extensions

views.py
from rest_framework_extensions.cache.mixins import CacheResponseMixin
class GoodsListViewSet(CacheResponseMixin, mixins.ListModelMixin, mixins.GoodsRetrieveModelMixin, viewsets.GenericViewSet):


# setting.py
REST_FRAMEWORK = {
'DEFAULT_CACHE_RESPONSE_TIMEOUT': 60*5, # 缓存5秒
}

简单配置即可用

drf缓存源码分析

  • 1.只对list和retrieve做了缓存处理配置沿用默认的配置和setting中restframework中的配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    class BaseCacheResponseMixin:
    object_cache_key_func = extensions_api_settings.DEFAULT_OBJECT_CACHE_KEY_FUNC
    list_cache_key_func = extensions_api_settings.DEFAULT_LIST_CACHE_KEY_FUNC
    object_cache_timeout = extensions_api_settings.DEFAULT_CACHE_RESPONSE_TIMEOUT
    list_cache_timeout = extensions_api_settings.DEFAULT_CACHE_RESPONSE_TIMEOUT


    class ListCacheResponseMixin(BaseCacheResponseMixin):
    @cache_response(key_func='list_cache_key_func', timeout='list_cache_timeout')
    def list(self, request, *args, **kwargs):
    return super().list(request, *args, **kwargs)


    class RetrieveCacheResponseMixin(BaseCacheResponseMixin):
    @cache_response(key_func='object_cache_key_func', timeout='object_cache_timeout')
    def retrieve(self, request, *args, **kwargs):
    return super().retrieve(request, *args, **kwargs)


    class CacheResponseMixin(RetrieveCacheResponseMixin,
    ListCacheResponseMixin):
    pass
  • 2.装饰器为一个cacheResponse对象,实例化时传入key_func用作生成key,和过期时间,当访问页面时,调用该对象的call()中的inner()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def __call__(self, func):
    this = self

    @wraps(func, assigned=WRAPPER_ASSIGNMENTS)
    def inner(self, request, *args, **kwargs):
    return this.process_cache_response(
    view_instance=self,
    view_method=func,
    request=request,
    args=args,
    kwargs=kwargs,
    )
    return inner
  • 3.通过默认的key_func计算出键和过期时间

    1
    2
    3
    4
    5
    6
    7
    8
    9
    key = self.calculate_key(
    view_instance=view_instance,
    view_method=view_method,
    request=request,
    args=args,
    kwargs=kwargs
    )

    timeout = self.calculate_timeout(view_instance=view_instance)
  • 4.获取key,如果没有执行视图函数并且未报错(status不为400、500)则存入缓存,如果有直接生成response返回

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    response_triple = self.cache.get(key)
    if not response_triple:
    # render response to create and cache the content byte string
    response = view_method(view_instance, request, *args, **kwargs)
    response = view_instance.finalize_response(request, response, *args, **kwargs)
    response.render()

    if not response.status_code >= 400 or self.cache_errors:
    response_triple = (
    response.rendered_content,
    response.status_code,
    response._headers.copy()
    )
    self.cache.set(key, response_triple, timeout)
    else:
    # build smaller Django HttpResponse
    content, status, headers = response_triple
    response = HttpResponse(content=content, status=status)
    for k, v in headers.values():
    response[k] = v

    if not hasattr(response, '_closable_objects'):
    response._closable_objects = []

    return response

网页限速设定

  • 避免恶意频繁访问导致的压力(爬虫、或者网页攻击)
  • 原理
    • 利用缓存存储根据用户id或者ip存储一个人访问该网页在限定时间中的次数,每次访问时对比缓存是否超过,如果超过次数则需等待设定时间
  • 该功能为drf自带,如果普通django视图需要自己手写一个限速功能

全局限速配置

  • 分为陌生用户和登录用户,可以限定次数每天访问多少次, 也可限定每分钟访问多少次,10/minute
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
    'rest_framework.throttling.AnonRateThrottle',
    'rest_framework.throttling.UserRateThrottle'
    ),
    'DEFAULT_THROTTLE_RATES': {
    'anon': '100/day',
    'user': '1000/day'
    }
    }

视图限速配置

from rest_framework.throttling import UserRateThrottle, AnonRateThrottle

class GoodsListViewSet(CacheResponseMixin, mixins.ListModelMixin, mixins.GoodsRetrieveModelMixin, viewsets.GenericViewSet):
“””the goods’s list, pagination, search, filter, ordering”””
queryset = Goods.objects.all() # 这里只是帮我们拼凑了sql脚本,并没有执行,只有在for循环的时候执行
throttle_classes = (UserRateThrottle, AnonRateThrottle)

分享到