中间件

Django中间件

  • 概念:Django中一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出无侵入的开发方式,增强了Django框架的健壮性。

Django内置的六个中间件方法

  1. 类似于Flask框架的请求钩子
1. 初始化
  • 无需要任何参数、服务器响应第一次请求的只调用一次

    def __init__():
        pass
    
2. 处理请求前
  • 在每个请求上调用,返回None 或 HttpResponse,需要接受请求对象

    def process_request(request):
      pass
      # 返回None / HttpResponse继续往下传递
        return None/HttpResponse
    
3.处理视图前
  • 在每个请求上调用, 返回None 或者 HttpResponse。

  • 接收请求参数:请求对象、请求的视图函数、请求视图参数

    def process_view(request, view_func, view_args, view_kwargs):
        pass
        return HttpResponse
    
4.处理模版响应前
  • 在每个请求上调用,返回实现了的render 方法的响应对象。

  • 请求参数:请求对象、响应对象

    def process_templates_response(request, response):
        pass
        return
    
5.处理响应后
  • 所有的响应返回浏览器之前被调用,在每个请求上调用,返回HttpResponse

  • 请求参数:请求对象、响应对象

    def process_response(request, response):
        pass
        return HttpResponse
    
6.异常处理
  • 当视图中抛出异常时候调用,在每个请求视图上调用,返回一个HttpResponse对象

  • 请求参数:请求对象、抛出异常

    def process_response(request, exception):
        pass
      return HttpResponse
    

自定中间件的定义方法

1.自定义
  • 定义一个中间件工厂函数、然后返回一个可以别出调用的中间件

  • 中间件工厂函数需要接受一个可以调用的get_response对象

  • 返回的中间件也是一个可以调用的对象,并像视图一样需要接受一个request对象参数,返回一个response对象

    # 本质:中间件就是一个装饰器,get_response:就是视图函数
    def my_middleware(get_response):
    
        # 1.仅在Django第一次配置初始化的时候执行一次,在DEBUG模式下会执行两次init
        print('init')
    
        def middleware(request):
            # 2.每个请求匹配到URL处理视图函数之前被调用
            print('before request 被调用前')
    
            response = get_response(request)
    
            # 3.每个请求处理视图函数之后被调用
            print('after request 被调用后')
            return response
        return middleware
    
  • 定义好的中间件需要在settings.py文件中注册

  • 定义多个中间件执行顺序:请求视图前,中间由上至下执行。请求视图后,中间件由下至上执行。

2.使用场景
  • 异常处理的方法的重写,因为原有的中间件不能捕获数据库错误

    # 添加Django REST framework的默认异常处理方法,redis和mysql异常
    from rest_framework.views import exception_handler as drf_exception_handler
    import logging
    from django.db import DatabaseError
    from redis.exceptions import RedisError
    from rest_framework.response import Response
    from rest_framework import status
    
    # 获取在配置文件中定义的logger,用来记录日志
    logger = logging.getLogger('django')
    
    
    def exception_handler(exc, context):
        """
        自定义异常处理
        :param exc: 异常
        :param context: 抛出异常的上下文
        :return: Response响应对象
        """
        # 调用drf框架原生的异常处理方法
        response = drf_exception_handler(exc, context)
    
        if response is None:
            view = context['view']
    
            if isinstance(exc, DatabaseError) or isinstance(exc, RedisError):
                # 数据库异常
                logger.error('[%s] %s' % (view, exc))
                response = Response({'message': '服务器内部错误'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)
    
        return response
    

Flask 请求钩子

1. 概念

  1. 在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理,比如
  • 在请求开始时,建立数据库连接;
  • 在请求开始时,根据需求进行权限校验;
  • 在请求结束时,指定数据的交互格式;
  1. 为了让每个视图函数避免编写重复功能的代码,Flask提供了通用设施的功能,即请求钩子。
  2. 请求钩子是通过装饰器的形式实现

2. Flask四种请求钩子

  1. before_first_request

    # 在第一次请求之前会调用(在发起请求之前就执行该请求钩子)
    # 应用地方:程序的初始化操作(一些准备工作,数据的链接请求或扫尾工作)
    @app.before_first_request
    def before_first_request():
        print('before_first_request') 
    
  2. before_request

    # 在每一次请求之前会调用
    # 应用:用户的权限验证
    @app.before_request
    def before_request():
        #  在这里可以做一些判断,这里使用return 后面的都不会执行(视图函数都不会进入)
        print('before_request')
        # if ....
        # return 'hehe'
        #  return判断以后,后面的接口就不会进入,做用户的黑名单校验
    
  3. after_request

    # 在每次请求执行之后执行
    @app.after_request
    def after_request(response):
        print('after_request')
        # 这里可以对响应对象做处理--->一般都是对响应做处理
        # 对所有返回的json数据进行处理(所有的都处理掉)
        response.headers["Content-Type"] = "application/json"
        return response
    
  4. teardown_request

    # 在每次请求执行的最后执行,如果服务器出现错误,这里也可以获取
    @app.teardown_request
    # @app.errorhandler
    def teardown_request(error):
        # 可以记录错误
        # 以后可能会用到请求数据库的自动提交
        print('teardown_request:%s' % error)
    

Spider中间件

1. 爬虫中间件

  1. 当爬虫创建时回调

    @classmethod
    def from_crawler(cls, crawler):
        """当爬虫被创建是回调"""
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s
    
  2. 进入爬虫回调函数

    def process_spider_input(self, response, spider):
        """
            1。响应对象 进入 爬虫时 回调
            2。返回None 或者 抛出异常--》None时继续往下执行
            """
        # Called for each response that goes through the spider
        # middleware and into the spider.
    
        # Should return None or raise an exception.
        return None
    
  3. 爬虫返回数据到引擎回调

    def process_spider_output(self, response, result, spider):
        """
            当爬虫 返回 数据给引擎的时候 回调
            Request, dict or Item objects
            :return:必须返回 请求对象, 字典对象, item数据模型对象
            """
        # Called with the results returned from the Spider, after
        # it has processed the response.
    
        # Must return an iterable of Request, dict or Item objects.
        for i in result:
            yield i
    
  4. 处理引擎首次获取start_url 构建 request 对象回调

    def process_start_requests(self, start_requests, spider):
        """处理引擎首次 获取 start_url构建 request 对象时 回调"""
        # 也要经过爬虫中间件
        # Called with the start requests of the spider, and works
        # similarly to the process_spider_output() method, except
        # that it doesn’t have a response associated.
    
        # Must return only requests (not items).
        for r in start_requests:
            yield r
    

2. 下载中间件

  1. spider创建 初始化

    @classmethod
    def from_crawler(cls, crawler):
        """当spider 被创建时,回调此方法,一般初始化方法"""
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s
    
  2. 引擎把请求 request 对象传递给下载器请求

    def process_request(self, request, spider):
        """
            当引擎把请求 request 传递给 下载器时候回调
            返回:
            None:继续处理请求
            Response:把响应对象还给引擎,并且引擎会把数据传递给爬虫
            Request:把请求对象还给引擎, 引擎会重新放入请求调度器队列中
            raise IgnoreRequest:触发异常处理,会回调函数process_exception来处理异常
            """
    
        # Called for each request that goes through the downloader
        # middleware.
    
        # Must either:
        # - return None: continue processing this request
        # - or return a Response object
        # - or return a Request object
        # - or raise IgnoreRequest: process_exception() methods of
        #   installed downloader middleware will be called
        return None
    
  3. 下载器,完成请求返回引擎响应对象

    def process_response(self, request, response, spider):
        """当下载器完成,返回给引擎响应对象时 回调
            返回:
            Response:把响应对象还给引擎,并且引擎会把数据传递给爬虫
            Request:把请求对象还给引擎, 引擎会重新放入请求调度器队列中, 继续发起请求
            """
        # Called with the response returned from the downloader.
    
        # Must either;
        # - return a Response object
        # - return a Request object
        # - or raise IgnoreRequest
        return response
    
  4. 处理异常

    def process_exception(self, request, exception, spider):
        """处理异常函数
            None:继续处理这个异常,向下一个中间件处理异常
            Response:停止异常传递
            Request:停止异常传递"""
        # Called when a download handler or a process_request()
        # (from other downloader middleware) raises an exception.
    
        # Must either:
        # - return None: continue processing this exception
        # - return a Response object: stops process_exception() chain
        # - return a Request object: stops process_exception() chain
        pass
    

你可能感兴趣的:(中间件)