zoukankan      html  css  js  c++  java
  • [python] pprika:基于werkzeug编写的web框架(3) ——错误处理

    错误处理示例

    from pprika import PPrika
    
    app = PPrika()
    
    
    @app.error_handler(404)
    def not_found(e):
        print(e)
        return repr(e)
    
    
    if __name__ == '__main__':
        app.run()

    与flask一样,通过error_handler装饰器来注册错误处理函数。该装饰器接受一个HTTP错误码或异常类(Exception)作为参数,会将发生的具体错误对象传递给处理函数。

    上述代码指当发生404错误时以not_found作为处理函数,其返回值跟视图函数一样会被处理成响应返回,而error_handler只是 register_error_handler 的装饰器版本,上方错误注册可改写成 app.register_error_handler(404, not_found) ,因此重点讲述register_error_handler。

    register_error_handler

    def register_error_handler(self, code_or_exception, func, field=None):
        if isinstance(code_or_exception, Exception):
            raise ValueError(f"""
                不可注册异常实例: {repr(code_or_exception)},
                只能是异常类或HTTP错误码
            """)
    
        exc_class, code = self._get_exc_class_and_code(code_or_exception)

    field参数表示该错误处理规则的适用范围,为None时表示作用于全局(app);为str时是蓝图名,表示仅作用于该蓝图(blueprint)内,非None的情况之后讲蓝图的时候会再提及。

    注意到其中调用了 _get_exc_class_and_code,它会根据错误码或者异常类其中一个尝试补出对应的另一个,比如本例中code_or_exception=404,经过该函数处理会补出 werkzeug.exceptions.NotFound。

    依据错误码得到异常类主要通过 werkzeug.exceptions 包中的一个字典default_exceptions,它以{http_error_code: exception_class}的形式记录了错误码与对应异常类的映射,反过来若异常类为HTTPException子类则e.code即为错误码,其他异常就统一将错误码当做None。具体实现方法与flask同名函数几乎一样,不再赘述。

        handlers = self.error_handlers.setdefault(field, {}).setdefault(code, {})
        handlers[exc_class] = func

    紧接上文,error_handlers是一个字典:{field: {status: {error: function}}},通过作用范围、错误码、具体错误类三层记录该错误类exc_class具体的处理函数func,这样一个错误处理函数就注册好了。

    接下来会讲述错误发生时的处理方式。

     handle_user_exception

    这是上一篇提到的dispatch_request内部的错误处理函数,也是内层错误处理

    dispatch_request内部片段↓↓↓

        try:
            endpoint, args = request.rule.endpoint, request.view_args
            rv = self.view_functions[endpoint](**args)
        except Exception as e:
            rv = self.handle_user_exception(e)

    当该过程(尤其指视图函数被调用时)产生的异常会被捕捉交给 handle_user_exception 处理。

    def handle_user_exception(self, e):
        handler = self._find_error_handler(e)
        if handler is not None:
            return handler(e)
        raise e

    该函数负责的是像本实例中通过error_handler装饰器或register_error_handler方法注册过的错误,若该错误未被注册将再次将其抛出。

    其中 _find_error_handler 内部先通过python内置的type函数得到异常类exc_class

    ,再通过上述的 _get_exc_class_and_code方法获得错误码code。

    由于一个错误可能在不同范围、以不同错误码注册过,因此查找时以错误码取code、None,在此基础上再以field取blueprint(表蓝图范围)、取None(表全局范围)的顺序在 self.error_handlers 中查找处理函数,若找不到则按None返回。具体实现方法同样与flask同名函数几乎一样,暂且略过,之后讲述restful部分时可能会有补充。

    handle_exception

    该函数作为外层错误处理器受 wsgi_app 调用,处理 handle_user_exception 无法处理的,或处理过程中再次发生的异常

    wsgi_app内部片段(去掉了不相关的)↓↓↓

        try:
            rv = self.dispatch_request()
            response = make_response(rv)
        except Exception as e:
            response = self.handle_exception(e)

    与handle_user_exception配合形成两层的错误处理,确保错误能正确响应

    下方是其实现原理

    def handle_exception(self, e):
        if isinstance(e, HTTPException):
            return e

    首先判断如果是HTTPException或其子类实例则直接返回

        server_error = InternalServerError()
        server_error.original_exception = e
    
        handler = self._find_error_handler(e) or self._find_error_handler(server_error)

    到了这一步说明该错误可能没有对应的错误处理器,也不是能直接作为response的HTTPException,那就统一当做 '500 InternalServerError' 响应,并在此尝试获取其handler(以原错误先尝试获取是考虑到可能是handle_user_exception处理中的再次发生的异常)

        if handler is not None:
            server_error = handler(server_error)
        else:
            print_exception(*exc_info())
    
        return make_response(server_error)

    最后若能找到handler则将返回值生成make_response并返回,否则说明不能自行处理该错误,打印出Traceback并直接返回InternalServerError(make_response内部也会把HTTPException这类的直接返回)。

    注意此处不能将无法处理的server_error再次raise并同时returnmake_response(server_error),即便使用try...finally也不行,raise与return不共存。但又需要显示错误信息(traceback),故通过exc_info得到traceback信息并由print_excption打印出来。

    from sys import exc_info
    from traceback import print_exception

    这点与flask不同,它利用self.propagate_exceptions决定是否再次抛出,self.log_exception、self.logger对该错误进行记录,更加细致,具体的没有深入了...

    结语

    至此错误处理部分结束,不过这部分之后在将restful时会有进一步的补充,接下来先讲讲请求上下文。

    [python] pprika:基于werkzeug编写的web框架(4) ——请求上下文与helpers

     

  • 相关阅读:
    对文件上传使用表单验证
    文件上传
    自定义验证器
    WTForms常用的验证器
    Eclipse自动补全+常用快捷键
    JNI笔记
    cocos2d 2.2.6 win7下的配置
    cocos2d 3.6 win7下的配置
    python--文件删除、判断目录存在、字符串替换
    只是一个文件节点类为了项目的数据处理
  • 原文地址:https://www.cnblogs.com/Stareven233/p/12971882.html
Copyright © 2011-2022 走看看