| 
 对于异常,通常可以分为两类:一类是可以预知的异常,我们通常会用try...except....捕捉,第二类是未知的error,我们是无法预知的。  
    try:  
      code block  
    except A:  
      except A handle  
    except:  
      other except  
    else:  
      if no exception, excute here  
    finally:  
      code  
    对于try....except捕捉异常,如果在try中发生了异常,会在except中捕捉到,并处理。如果没有发生异常,会执行else语句  
    但是不论异常是否发生,都会执行finally语句,所以我们一般会在finally语句中释放资源。  
但是,如果所有的代码中我们都加上各种异常捕获,会显得代码比较啰嗦,其实我们是可以将异常处理的逻辑提取出来,统一处理的。  
1)下面我们先自定义已知异常处理,继承自werkzeug.exceptions下面的HTTPException  
  from flask import request, json  
  from werkzeug.exceptions import HTTPException  
  def APIException(HTTPException):  
    code = 500  
    msg = "sorry, we made a mistake"  
    error_code = 500  
    def __init__(msg=None, code=None, error_code=None):  
      if code:  
        self.code=code  
      if msg:  
        self.msg=msg  
      if error_code:  
        self.error_code = error_code  
      super(APIException, self).__init__(self.msg, None)  
    # 根据restful的特性,需要不论输入还是输出都需要是json格式,所以我们这里重写get_body方法,将返回值定义为json格式  
    def get_body(self, environ):  
      resp = dict(  
        msg = self.msg,  
        error_code = self.error_code,  
        request = request.method + " "+ self.get_url_without_param() # 告诉前端,是哪个接口除了问题  
      )  
      return json.dumps(resp)  
    # 重写get_header方法,告诉浏览器返回的是json格式,按照json格式解析  
    def get_header():  
      return [("content-type","application/json")]  
    @staticmethod  
    def get_url_without_param():  
      full_url = str(request.full_path)  
      main_url = full_url.split("?")  
      return main_url[0]  
   
  要使用我们的APIException也是很简单的,如要处理参数异常,我们可以定义一个ParamError的类,继承自APIException  
    class ParamError(APIException):  
      code =400  
      msg = "invalid parameters"  
      error_code = 1000 # 自定义  
   然后在捕获到参数异常的时候,直接抛出我们自定义的ParamError()即可  
  如果是前端传递过来的参数验证出异常的话,要使用我们的ParamException,需要手动的抛出异常,但是默认的wtforms会将错误信息放到errors中,而不会抛出异常,所以我们还需要重写wtforms的验证方法  
    from wtforms import Form  
    class BaseForm(Form):  
      def __init__(self, data):  
        # 调用父类的init方法  
        super(BaseForm, self).__init__(data = data)  
      def validate_for_api(self,):  
        # 调用父类的验证方法,如果验证有问题,主动抛出ParamError异常 并将errors作为msg参数传递过去  
        valid = super(BaseForm, self).validate()  
        if not valid:  
          # 这里的self 就是我们常规说的验证的form  
          raise ParamError(msg = self.errors)  
        return self  
  后面所有form直接继承此BaseForm即可,然后在要验证参数的地方调用重写的validate_for_api即可。  
2)我们定义个全局函数去统一处理所有的异常  
  from werkzeug.exceptions import HTTPException  
  # 使用装饰器去捕捉异常   
  @app.errorhandler(Exception)  
  def errorHandler(e):  
    if isinstance(e, APIException):  
      # 已知异常  
      return e  
    if isinstance(e, HTTPException):  
      # HTTP异常  
      code = e.code  
      msg = e.description  
      error_code = 1007 # 自定义  
      return APIException(msg, code, error_code)  
    else:  
      # 其他未知异常,此处需要分是生产环境还是开发环境,如果是生产环境,返回json格式的异常,如果是开发环境,我们需要详细的异常说明去分析异常原因  
      if not app.config["DEBUG"]:  
        return ServerError()  # 类似于上面定义的ParamError,自定义ServerError的code和msg  
      else:  
        raise e  
   
这样全局异常就处理完成,不论是发生何种异常,我们都能捕捉到并进行处理了。  
        
      
   |