django 1.11

中间件的制造工厂是一个方法接收get_response 作为入参返回一个中间件。一个中间件是一个可调用的对象,接收一个request返回一个response,就像view.

 

middleware也可以写作一个方法

 

def simple_middleware(get_response):

 

  def middleware(request):

 

    response=get_response(request)

 

    return response

 

  return middleware 

 

或者写作一个类class

 

class SimpleMiddleware(object):

 

  def __init__(self,get_response):

 

    self.get_response=get_response

 

  def __call__(self,request):

 

    response=self.get_response(request)

 

    return response

 

get_response由django提供,它可能是一个view(如果这个middleware排在最后)也可能是链条中的下一个middleware。当前的中间件不需要知道它具体是什么,它仅仅代表了生成的结果

 

django只需要get_response一个参数来初始化中间件,所以你定义__init__()时不能添加其他的参数。

 

__call__()方法每次请求都会被调用一次,__init__()方法仅在web服务器开启的时候被调用一次。

 

当middleware不应该被启用时,middleware的__init__方法会抛出MiddlewareNotUsed,然后django会将此middleware从中间价进程中移除,并且会产生一条debug级别的日志。

 

 

在MIDDLEWARE列表中的的中间件的顺序会影响他们依赖的中间件。比如AuthenticationMiddleware在session中存储了已认证的用户,所以它必须在SessionMiddleware之后运行

在request阶段,请求先从MIDDLEWARE列表中由上到下穿过,然后到达view,然后response将由middleware中由下到上穿过返回.

如果有一个middleware在request阶段没有调用get_response,直接返回response,那么剩下的middleware(包括view)也就不会见到request或response了。这个response会倒序穿过request穿过的middleware.

 

 

class形式的middleware通常包括一下处理方法:

process_request(request)

process_reponse(request,response)

process_view(request,view_func,view_args,view_kwargs) 在调用view之前被调用

view_func :一个真正的方法对象,而不是方法名字的字符串

view_args和view_kwargs分别是view_func的位置入参和关键字入参,他们都不需要传入request

它返回 None和HttpResponse中的一个,如果是none则继续调用下一个middleware的process_view,如果是HttpResponse则不会再调用view而是调用response middleeware来处理response后直接返回结果

如果通过middleware在调用view之前访问了request.POST,将会阻止任何view在运行过程中可能修改request的上传器的行为

CscrViewMiddleware可以看作一个异常处理器,它提供csrf_exempt()和csrf_protect()装饰器可以让view明确控制CSRF应该确认的点

process_exception(request,exception) 当view抛出异常时 被调用

它返回None和HttpResponse中的一个,如果返回Httpresponse,则reponse middleware继续被应用于该response,否则由默认的异常处理来处理它。

response经过中间件的顺序是由下向上,process_exception被调用的顺序也是由下向上。如果一个exception middleware返回一个response,那么该中间件之上的response中间件就不会被调用了。

process_template_response(request,response)在view刚被调用完后被调用,执行顺序同response

request: HttpRequest对象。

response:由view或middleware返回的TemplateResponse对象。如果一个response实例有render()方法,就表明它是一个TemplateResponse对象。

它必须返回一个执行了render方法的response。 在该方法中可以改变 传入的response的response.template_name 和response.context_data 或者创建一个新的Tempalteresponse返回

response不需要明确的被渲染,一旦template response middleware被调用,response会自动被选染。

 TemplateResponse保留了view计算出reponse的上下文,最后输出response是直到它被需要时才在reponse process中计算完成的

 处理  流式reponse

与HttpResponse不同,StreamingHttpResponse没有属性content.当middleware需要使用content时,必须判断response是否为streaming response 来响应的调整他们的行为。

if reponse.streaming:

  reponse.streaming_content=wrap_streaming_content(response.streaming_content)

else:

  reponse.content=alter_content(reponse.content)

应该将streaming reponse 预估为较大的,内存无法承担的对象,应使用generator来逐步使用,如下:

def wrap_streaming_content(content):

  for chunk in content:
    yield alter_content(chunk)

 

处理异常

django会自动将view或middleware产生的异常转化成对应的 http错误 响应码页面

明确的异常映射成4xx错误码,未知异常映射成500错误码

这种映射发生在每个middleware之前和之后,这个每个middleware都可以确定通过get_reponse可以收到http reponse,而不用使用try/except来处理get_reponse的返回值,打比方说后面的middleware中抛出一个Http404的异常,当前的middleware不会接收到这个异常,而是获取到一个Httpresponse对象,及一个404的status_code。

 

 缓存中间件

如果开启了缓存中间键,它会作用于url映射的每个页面

规范的设置方式是 将UpdateCacheMiddleware作为第一个中间键,FetchFromCacheMiddleware作为最后一个,以便request在最后一步经过FetchFromCacheMiddleware来通过缓存返回response ,response在最后一步经过UpdateCacheMiddleware来更新一个可缓存的response的缓存:

MIDDLEWARE=[

'django.middleware.cache.UpdateCacheMiddleware',

...

'django.middleware.cache.FetchFromCacheMiddleware'

]

只有请求方式为get或head且状态码为200的内容会被缓存

页面缓存的保存秒数 由response响应头"Cache-Control"的"max-age"属性值决定,如果没有找到该属性则根据settings.py中的CACHE_MIDDLEWARE_SECONDS的值来确定

这个中间件期望请求的响应头与get类型请求的响应头几乎一致

当发生攻击时,process_request将会浅复制一个原始的response对象,返回。

页面将会根据请求头在response's "vary" header中列出的内容来缓存

这个中间键也可以设置reponse响应头的ETag,Last-Modified,Expires和Cache-Control值

使用时,在view中from django.views.decorators.cache import cache_page ,然后在需要缓存的函数页面上加上 @cache_page(seconds)即可,seconds表示缓存的有效秒数。

 

在settings.py中的CACHES设置 缓存的数据应该保存在哪里,数据库,文件系统或直接保存到内存。

可用的值有:

Memcached

 django默认支持的快速,高效的缓存 key-value数据库,完全基于内存的缓存服务,它只是提供了一个快速的删除,检索,添加 缓存里数据的接口。

安装完Memcached 后需要安装相关依赖 ,常用的有python-memcached和pylibmc . 

在django中起用Memcached 作为缓存,将backend设置为django.core.cache.backends.memcached.MemcachedCache或者

django.core.cache.backends.memcached.PlLibMCCache

location设置为‘ip:port',或者 unix:path ,path为Memcached Unix socket文件的路径(例 'unix:/tmp/memcached.sock') ,例

CACHES={

  'default':{

    'BACKEND':'django.core.cache.backends.memcached.MemcachedCache',

    'LOCATION':'127.0.0.1:11211',

    }

  }

当backends使用pylibmc时,LOCATION应设置为’/tmp/memcached.sock'

Memcached有一个比较好的特性是可以在多个服务器上共享缓存。这意味着可以在不同的服务器上各自运行一个Memcache,不需要复制缓存值,应用工程可以把这个集群看作单个的缓存服务器,启用这种特性需要将所有的地址添加进LOCATION,可以以list或分号,逗号分隔的字符串表示。如:

CACHES={

  ‘default':{

    'BACKEDN':'django.core.cache.backends.memcached.MemcachedCache',

    'LOCATION':[

          '172.19.26.240:11211',

          '172.19.26.142:11212',

          '172.19.26.244:11213',

          ]

      }

    }

Memcached是一个基于缓存的数据库,所以如果服务器宕机了,存储于其中的数据就会丢失。

中间件的应用场景,一般用来做IP限制(放在中间件的列表中,阻止某些IP访问;),URL过滤(用户信息验证),缓存。

 

 posted on 2018-10-25 15:13  庭明  阅读(193)  评论(0编辑  收藏  举报