最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Flask開(kāi)發(fā)技巧之異常處理

 更新時(shí)間:2021年06月15日 17:34:17   作者:luyuze95  
Flask是一個(gè)微型的Python開(kāi)發(fā)的Web框架,基于Werkzeug WSGI工具箱和Jinja2 模板引擎。Flask使用BSD授權(quán)。Flask也被稱(chēng)為“microframework”,因?yàn)樗褂煤?jiǎn)單的核心,用extension增加其他功能。本文主要介紹了它的異常處理機(jī)制

一、Flask內(nèi)置異常處理

要想在Flask中處理好異常,有一套自己的異常處理機(jī)制,首先,我們必須先知道Flask自己是如何處理異常的。去flask的源碼里找一找會(huì)發(fā)現(xiàn),在flask源碼的app.py文件下,有很多會(huì)拋出異常的方法,其中拿一個(gè)舉例:

def handle_exception(self, e):
"""Default exception handling that kicks in when an exception
occurs that is not caught.  In debug mode the exception will
be re-raised immediately, otherwise it is logged and the handler
for a 500 internal server error is used.  If no such handler
exists, a default 500 internal server error message is displayed.

.. versionadded:: 0.3
"""
exc_type, exc_value, tb = sys.exc_info()

got_request_exception.send(self, exception=e)
handler = self._find_error_handler(InternalServerError())

if self.propagate_exceptions:
    # if we want to repropagate the exception, we can attempt to
    # raise it with the whole traceback in case we can do that
    # (the function was actually called from the except part)
    # otherwise, we just raise the error again
    if exc_value is e:
        reraise(exc_type, exc_value, tb)
    else:
        raise e

self.log_exception((exc_type, exc_value, tb))
if handler is None:
    return InternalServerError()
return self.finalize_request(handler(e), from_error_handler=True)

我們發(fā)現(xiàn)在flask內(nèi)部對(duì)于500異常,會(huì)拋出這樣一個(gè)錯(cuò)誤類(lèi)InternalServerError()

class InternalServerError(HTTPException):

    ......

至此我們發(fā)現(xiàn)flask內(nèi)部異常通過(guò)繼承這個(gè)HTTPException類(lèi)來(lái)處理,那么這個(gè)HTTPException類(lèi)就是我們研究的重點(diǎn)。

二、HTTPException類(lèi)分析

@implements_to_string
class HTTPException(Exception):
    """Baseclass for all HTTP exceptions.  This exception can be called as WSGI
    application to render a default error page or you can catch the subclasses
    of it independently and render nicer error messages.
    """

    code = None
    description = None

    def __init__(self, description=None, response=None):
        super(HTTPException, self).__init__()
        if description is not None:
            self.description = description
        self.response = response

    @classmethod
    def wrap(cls, exception, name=None):
        """Create an exception that is a subclass of the calling HTTP
        exception and the ``exception`` argument.

        The first argument to the class will be passed to the
        wrapped ``exception``, the rest to the HTTP exception. If
        ``e.args`` is not empty and ``e.show_exception`` is ``True``,
        the wrapped exception message is added to the HTTP error
        description.

        .. versionchanged:: 0.15.5
            The ``show_exception`` attribute controls whether the
            description includes the wrapped exception message.

        .. versionchanged:: 0.15.0
            The description includes the wrapped exception message.
        """

        class newcls(cls, exception):
            _description = cls.description
            show_exception = False

            def __init__(self, arg=None, *args, **kwargs):
                super(cls, self).__init__(*args, **kwargs)

                if arg is None:
                    exception.__init__(self)
                else:
                    exception.__init__(self, arg)

            @property
            def description(self):
                if self.show_exception:
                    return "{}\n{}: {}".format(
                        self._description, exception.__name__, exception.__str__(self)
                    )

                return self._description

            @description.setter
            def description(self, value):
                self._description = value

        newcls.__module__ = sys._getframe(1).f_globals.get("__name__")
        name = name or cls.__name__ + exception.__name__
        newcls.__name__ = newcls.__qualname__ = name
        return newcls

    @property
    def name(self):
        """The status name."""
        from .http import HTTP_STATUS_CODES

        return HTTP_STATUS_CODES.get(self.code, "Unknown Error")

    def get_description(self, environ=None):
        """Get the description."""
        return u"<p>%s</p>" % escape(self.description).replace("\n", "<br>")

    def get_body(self, environ=None):
        """Get the HTML body."""
        return text_type(
            (
                u'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n'
                u"<title>%(code)s %(name)s</title>\n"
                u"<h1>%(name)s</h1>\n"
                u"%(description)s\n"
            )
            % {
                "code": self.code,
                "name": escape(self.name),
                "description": self.get_description(environ),
            }
        )

    def get_headers(self, environ=None):
        """Get a list of headers."""
        return [("Content-Type", "text/html; charset=utf-8")]

    def get_response(self, environ=None):
        """Get a response object.  If one was passed to the exception
        it's returned directly.

        :param environ: the optional environ for the request.  This
                        can be used to modify the response depending
                        on how the request looked like.
        :return: a :class:`Response` object or a subclass thereof.
        """
        from .wrappers.response import Response

        if self.response is not None:
            return self.response
        if environ is not None:
            environ = _get_environ(environ)
        headers = self.get_headers(environ)
        return Response(self.get_body(environ), self.code, headers)
  • 截取這個(gè)類(lèi)比較重要的幾個(gè)方法分析,get_headers方法定義了這個(gè)返回的響應(yīng)頭,返回的是html文檔。
  • get_body方法定義了返回的響應(yīng)體,對(duì)應(yīng)也是一段html的內(nèi)容。
  • 最后在Response中將響應(yīng)體,狀態(tài)碼,響應(yīng)頭定義好返回。

分析至此,其實(shí)這個(gè)HTTPException中做的事也不難理解,就是定義好響應(yīng)體,狀態(tài)碼,還有響應(yīng)頭,做了一個(gè)返回。當(dāng)然這個(gè)類(lèi)返回是html類(lèi)型的,現(xiàn)在前后端分離交互都是json形式的返回,所以我們可以繼承自這個(gè)類(lèi),定義我們自己的異常處理類(lèi)。

三、自定義異常處理類(lèi)

首先我們理解我們自己的這個(gè)異常處理類(lèi),應(yīng)該繼承自HTTPException來(lái)改寫(xiě)。而我們自定義的內(nèi)容應(yīng)該包含以下幾點(diǎn):

  • 需要定義我們自己想要返回的錯(cuò)誤信息的json格式,比如內(nèi)部錯(cuò)誤碼、錯(cuò)誤信息等我們想記錄的信息。
  • 需要更改返回的響應(yīng)頭,返回json格式的信息響應(yīng)頭就應(yīng)該設(shè)為'Content-Type': 'application/json'
  • 同樣需要和HTTPException一樣定義好狀態(tài)碼

如下定義我們自己的異常類(lèi)APIException,返回的信息包括內(nèi)部錯(cuò)誤碼,錯(cuò)誤信息,請(qǐng)求的url

class APIException(HTTPException):
    code = 500
    msg = 'sorry, we made a mistake!'
    error_code = 999

    def __init__(self, msg=None, code=None, error_code=None, headers=None):
        if code:
            self.code = code
        if error_code:
            self.error_code = error_code
        if msg:
            self.msg = msg
        super(APIException, self).__init__(msg, None)

    def get_body(self, environ=None):
        body = dict(
            msg=self.msg,
            error_code=self.error_code,
            request=request.method + ' ' + self.get_url_no_param()
        )
        text = json.dumps(body)
        return text

    def get_headers(self, environ=None):
        """Get a list of headers."""
        return [('Content-Type', 'application/json')]

    @staticmethod
    def get_url_no_param():
        full_path = str(request.full_path)
        main_path = full_path.split('?')
        return main_path[0]

四、方便的定義自己的錯(cuò)誤類(lèi)

有了上面我們改寫(xiě)好的APIException類(lèi),我們就可以自由的定義各種狀態(tài)碼的錯(cuò)誤以及對(duì)應(yīng)的錯(cuò)誤信息,然后在合適的位置拋出。比如:

class Success(APIException):
    code = 201
    msg = 'ok'
    error_code = 0


class DeleteSuccess(APIException):
    code = 202
    msg = 'delete ok'
    error_code = 1


class UpdateSuccess(APIException):
    code = 200
    msg = 'update ok'
    error_code = 2


class ServerError(APIException):
    code = 500
    msg = 'sorry, we made a mistake!'
    error_code = 999


class ParameterException(APIException):
    code = 400
    msg = 'invalid parameter'
    error_code = 1000


class NotFound(APIException):
    code = 404
    msg = 'the resource are not found'
    error_code = 1001


class AuthFailed(APIException):
    code = 401
    msg = 'authorization failed'
    error_code = 1005


class Forbidden(APIException):
    code = 403
    error_code = 1004
    msg = 'forbidden, not in scope'

有了這些自定義的錯(cuò)誤類(lèi),我們不僅可以直接在需要的地方拋出,而且有了自定義的錯(cuò)誤碼,發(fā)生錯(cuò)誤時(shí),只要對(duì)照錯(cuò)誤碼去查找對(duì)應(yīng)的錯(cuò)誤類(lèi),非常方便。而且特別說(shuō)明的是,雖然說(shuō)是錯(cuò)誤類(lèi),但是也是可以定義響應(yīng)成功的返回的,比如上面定義的200,201的類(lèi),同樣可以作為一個(gè)成功的返回。

使用演示:

user = User.query.first()
if not user:
    raise NotFound()

五、注意事項(xiàng)

盡管我們可以在我們認(rèn)為可能出錯(cuò)的所有地方,繼承自己的異常類(lèi),定義自己的錯(cuò)誤類(lèi),然后拋出,但是也不是所有的異常都是我們可以提前預(yù)知的。比如我們接受前端傳來(lái)的參數(shù),參數(shù)類(lèi)型或取值范圍不正確,這些我們可以預(yù)知并處理好,但是如果是邏輯處理中出現(xiàn)了問(wèn)題,這些不是我們程序員可以控制并處理。所以光有自定義錯(cuò)誤類(lèi)還不夠,我們還需要在全局捕獲異常來(lái)判斷,利用AOP思想。

# 全局錯(cuò)誤AOP處理
@app.errorhandler(Exception)
def framework_error(e):
    api_logger.error("error info: %s" % e) # 對(duì)錯(cuò)誤進(jìn)行日志記錄
    if isinstance(e, APIException):
        return e
    if isinstance(e, HTTPException):
        code = e.code
        msg = e.description
        error_code = 1007
        return APIException(msg, code, error_code)
    else:
        if not app.config['DEBUG']:
            return ServerError()
        else:
            return e

這里對(duì)于flask中拋出的所有的錯(cuò)誤進(jìn)行捕獲,然后先進(jìn)行日志的記錄。然后判斷如果是我們自定義的APIException,就直接返回。如果不是我們自定義的,但是是flask處理的HTTPException,包裝成我們自定義的APIException再返回。如果都不是的話(huà),說(shuō)明是服務(wù)器出現(xiàn)的其他錯(cuò)誤,問(wèn)題一般出在我們的代碼上,在生產(chǎn)環(huán)境下,一般統(tǒng)一返回一個(gè)500錯(cuò)誤,在調(diào)試模式下,可以原樣返回,便于我們定位修改自己的代碼。

以上就是詳解Flask開(kāi)發(fā)技巧之異常處理的詳細(xì)內(nèi)容,更多關(guān)于Flask異常處理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 使用Python從有道詞典網(wǎng)頁(yè)獲取單詞翻譯

    使用Python從有道詞典網(wǎng)頁(yè)獲取單詞翻譯

    這篇文章主要介紹了使用Python從有道詞典網(wǎng)頁(yè)獲取單詞翻譯的相關(guān)資料,需要的朋友可以參考下
    2016-07-07
  • 在Python的Django框架下使用django-tagging的教程

    在Python的Django框架下使用django-tagging的教程

    這篇文章主要介紹了在Python的Django框架下使用django-tagging的教程,針對(duì)網(wǎng)絡(luò)編程中的tag部分功能提供幫助,需要的朋友可以參考下
    2015-05-05
  • python實(shí)現(xiàn)小世界網(wǎng)絡(luò)生成

    python實(shí)現(xiàn)小世界網(wǎng)絡(luò)生成

    今天小編就為大家分享一篇python實(shí)現(xiàn)小世界網(wǎng)絡(luò)生成,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-11-11
  • Python打印異常信息的方法示例詳解

    Python打印異常信息的方法示例詳解

    在 Python 編程中,異常是指程序執(zhí)行過(guò)程中出現(xiàn)的錯(cuò)誤或異常情況,當(dāng)程序遇到異常時(shí),為了更好地調(diào)試和定位問(wèn)題,我們需要打印異常信息,本文將詳細(xì)介紹如何在 Python 中打印異常,并提供一些示例和注意事項(xiàng),需要的朋友可以參考下
    2023-12-12
  • PyQt5 關(guān)于Qt Designer的初步應(yīng)用和打包過(guò)程詳解

    PyQt5 關(guān)于Qt Designer的初步應(yīng)用和打包過(guò)程詳解

    Qt Designer中的操作方式十分靈活,其通過(guò)拖拽的方式放置控件可以隨時(shí)查看控件效果。這篇文章主要介紹了PyQt5 關(guān)于Qt Designer的初步應(yīng)用和打包,需要的朋友可以參考下
    2021-09-09
  • Python中用Ctrl+C終止多線(xiàn)程程序的問(wèn)題解決

    Python中用Ctrl+C終止多線(xiàn)程程序的問(wèn)題解決

    花了一天時(shí)間用python為服務(wù)寫(xiě)了個(gè)壓力測(cè)試。很簡(jiǎn)單,多線(xiàn)程向服務(wù)器發(fā)請(qǐng)求。但寫(xiě)完之后發(fā)現(xiàn)如果中途想停下來(lái),按Ctrl+C達(dá)不到效果,自然想到要用信號(hào)處理函數(shù)捕捉信號(hào),使線(xiàn)程都停下來(lái),問(wèn)題解決的方法請(qǐng)往下看:
    2013-03-03
  • Python中緩存lru_cache的基本介紹和講解

    Python中緩存lru_cache的基本介紹和講解

    緩存是一種將定量數(shù)據(jù)加以保存以備迎合后續(xù)請(qǐng)求的處理方式,旨在加快數(shù)據(jù)的檢索速度,下面這篇文章主要給大家介紹了關(guān)于Python中緩存lru_cache的基本介紹和講解的相關(guān)資料,需要的朋友可以參考下
    2022-01-01
  • python?yield迭代器詳解

    python?yield迭代器詳解

    帶有yield的函數(shù)在Python中被稱(chēng)之為generator(生成器),也就是說(shuō),當(dāng)你調(diào)用這個(gè)函數(shù)的時(shí)候,函數(shù)內(nèi)部的代碼并不立即執(zhí)行?,這個(gè)函數(shù)只是返回一個(gè)生成器
    2022-11-11
  • 詳解anaconda離線(xiàn)安裝pytorchGPU版

    詳解anaconda離線(xiàn)安裝pytorchGPU版

    這篇文章主要介紹了詳解anaconda離線(xiàn)安裝pytorchGPU版,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • 基于Python實(shí)現(xiàn)本地音樂(lè)播放器的制作

    基于Python實(shí)現(xiàn)本地音樂(lè)播放器的制作

    這篇文章主要介紹了如何利用Python實(shí)現(xiàn)本地音樂(lè)播放器的制作,并且可以選擇需要播放的音樂(lè)的路徑,選擇播放方式,感興趣的小伙伴可以了解一下
    2022-06-06

最新評(píng)論

奉节县| 宜州市| 交口县| 古交市| 石棉县| 读书| 桃江县| 华池县| 北票市| 德令哈市| 安福县| 石景山区| 志丹县| 米脂县| 平遥县| 黄浦区| 甘孜| 常德市| 乌兰浩特市| 行唐县| 上栗县| 贞丰县| 镇江市| 天柱县| 秦安县| 新民市| 吉林省| 藁城市| 曲水县| 攀枝花市| 营山县| 三亚市| 高阳县| 增城市| 科技| 克什克腾旗| 固阳县| 张家界市| 曲沃县| 镇康县| 根河市|