Python/GAE 网络请求错误处理
我正在使用Python在Google App Engine上开发一个应用程序。
我有一个处理程序,可以返回多种输出格式(目前是html和json),我正在测试系统中由于请求处理程序收到无效参数而导致的明显错误。
不过我觉得我现在的做法有点乱(见下面的代码):
class FeedHandler(webapp.RequestHandler):
def get(self):
app = self.request.get("id")
name = self.request.get("name")
output_type = self.request.get("output", default_value = "html")
pretty = self.request.get("pretty", default_value = "")
application = model.Application.GetByKey(app)
if application is None:
if output_type == "json":
self.response.out.write(simplejson.dumps({ "errorCode" : "Application not found."}))
self.set_status(404)
return
category = model.FeedCategory.GetByKey(application, name)
if category is None:
if output_type == "json":
self.response.out.write(simplejson.dumps({ "errorCode" : "Category not found."}))
self.set_status(404)
return
我正在针对每种输出类型和每个“断言”来处理不同的情况。
我希望能听到一些建议、模式和例子,看看如何能把这个问题理顺(我知道这样做将来会很难维护)。
我在考虑创建自定义异常,并使用一个装饰器自动处理错误信息的显示——我觉得这个主意不错,但我很想听听大家过去是怎么做的,有什么反馈和建议。
2 个回答
至少,你应该把重复的代码整理一下,比如:
if application is None:
if output_type == "json":
self.response.out.write(simplejson.dumps({ "errorCode" : "Application not found."}))
self.set_status(404)
return
把它放进一个辅助方法里:
def _Mayerr(self, result, msg):
if result is None:
if output_type == 'json':
self.response.out.write(simplejson.dumps(
{"errorCode": msg})
self.set_status(404)
return True
然后可以像这样调用它:
if self._Mayerr(application, "Application not found."):
return
除此之外,使用自定义异常(还有把所有处理程序用一个装饰器包裹起来,这样可以捕获异常并给出合适的错误信息)是一种很好的架构方式。虽然这样做会对你的代码进行更多的修改,但这比我刚才提到的简单整理要复杂一些。不过,现在多花点时间去做这些,可能会在未来避免你在应用程序中到处都写重复和模板化的错误处理代码,这样会更有效率!-)
这里有几个很实用的方法。第一个是 self.error(code)。默认情况下,这个方法只是设置状态码并清空输出缓冲区,但你可以重写这个方法,根据错误的类型输出自定义的错误页面。
第二个方法是 self.handle__exception(exception, debug_mode)。如果你的 get/post 等方法返回了未处理的异常,webapp 的框架会调用这个方法。默认情况下,它会调用 self.error(500) 并记录这个异常(如果调试模式开启的话,还会把它打印到输出中)。你可以重写这个方法,以你喜欢的方式处理异常。下面是一个示例,允许你为不同的状态抛出异常:
class StatusCodeException(Exception):
def __init__(self, code):
self.status_code = code
class RedirectException(StatusCodeException):
def __init__(self, location, status=302):
super(RedirectException, self).__init__(status)
self.location = location
class ForbiddenException(StatusCodeException):
def __init__(self):
super(ForbiddenException, self).__init__(403)
class ExtendedHandler(webapp.RequestHandler):
def handle_exception(self, exception, debug_mode):
if isinstance(exception, RedirectException):
self.redirect(exception.location)
else:
self.error(exception.status_code)