Flask源码异常处理问题
Flask version: 0.3
我事先在views.py
里面定义了如下的异常处理方法:
@app.errorhandler(404)
def page_not_found():
return "this page is not found.", 404
@app.errorhandler(500)
def page_error():
return "this page is error.", 500
#:: 这两个异常处理方法都是错误的,因为没有加参数。
先贴几段源码
#:: 片段1
def wsgi_app(self, environ, start_response):
with self.request_context(environ):
try:
rv = self.preprocess_request()
if rv is None:
rv = self.dispatch_request()
response = self.make_response(rv)
response = self.process_response(response)
except Exception, e:
response = self.make_response(self.handle_exception(e))
return response(environ, start_response)
#:: 片段2
def dispatch_request(self):
req = _request_ctx_stack.top.request
try:
if req.routing_exception is not None:
raise req.routing_exception #:: 抛出异常
return self.view_functions[req.endpoint](**req.view_args)
except HTTPException, e:
return self.handle_http_exception(e)
#:: 片段3
class _RequestContext(object):
def __init__(self, app, environ):
self.app = app
self.url_adapter = app.url_map.bind_to_environ(environ)
self.request = app.request_class(environ)
self.session = app.open_session(self.request)
if self.session is None:
self.session = _NullSession()
self.g = _RequestGlobals()
self.flashes = None
try:
self.request.endpoint, self.request.view_args = \
self.url_adapter.match() #:: 不匹配
except HTTPException, e:
print e.code, e.description
self.request.routing_exception = e
#:: 片段4
def handle_exception(self, e):
handler = self.error_handlers.get(500)
if self.debug:
raise
self.logger.error("hello")
self.logger.exception('Exception on %s [%s]' % (
request.path,
request.method
))
if handler is None:
return InternalServerError()
return handler(e) #:: handler不为None,之前定义了500的错误处理
然后我在浏览器输入了一个不存在的路由http://localhost:5000/test
,想看Flask如何异常处理。
请求过来之后会先执行片段1
, 然后代码走到片段3
请求上下文,片段3
中self.url_adapter.match()
抛出HTTPException
异常被捕获。然后执行到片段2
,然后抛出异常被片段1
捕获到执行片段4
,最后会执行到handler(e)
这条语句。
我的问题来了,因为我定义的500的错误处理里面,没有加参数,导致这条语句执行失败。
报了如下错误:
Traceback (most recent call last):
File "/Users/virtualenvs/full-stack/lib/python2.7/site-packages/werkzeug/serving.py", line 180, in run_wsgi
execute(self.server.app)
File "/Users/virtualenvs/full-stack/lib/python2.7/site-packages/werkzeug/serving.py", line 168, in execute
application_iter = app(environ, start_response)
File "/Users/virtualenvs/full-stack/flask0.3/examples/flaskr/flask.py", line 1435, in __call__
return self.wsgi_app(environ, start_response)
File "/Users/virtualenvs/full-stack/lib/python2.7/site-packages/werkzeug/wsgi.py", line 591, in __call__
return self.app(environ, start_response)
File "/Users/virtualenvs/full-stack/flask0.3/examples/flaskr/flask.py", line 1382, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/Users/virtualenvs/full-stack/flask0.3/examples/flaskr/flask.py", line 1266, in handle_exception
return handler(e)
TypeError: page_error() takes no arguments (1 given)
从Traceback
当中能看出最后也是这句的错误。然而浏览器还是返回了500的页面,返回的内容是Werkzeug
自定义的页面内容。
Internal Server Error
The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
既然程序都已经执行错误了,那为什么还能够返回HTTP Response
呢?
谢谢:-)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
你自己也说了返回的500是
Werkzeug
自定义的吧……这可以说明
Werkzeug
定义的函数捕获的,也是由Werkzeug
进行处理的注意
flask
是怎么创建WSGI
app的:可以看出是在
request_context
上下文中进行处理的,而异常是在except
中因为给自己定义的异常处理函数传入了参数引发的,不是在try
中,所以这个异常的三个参数exc_type, exc_value, exc_traceback
会被传入with
中的上下文的__exit__
方法(参考浅谈 Python 的 with 语句的“自定义上下文管理器”一段)。__exit__
方法最终会调用_request_ctx_stack.pop
。而_request_ctx_stack
的LocalStack
类是由Werkzeug
定义的。当__exit__
方法内部也没有处理该异常时,这个异常最终会交由with
语句块外的代码处理,所以此处的异常最终可能是由Werkzeug
中的LocalStack
类进行处理或者是你运行时使用的WSGI
服务器内部调用了Werkzeug
的异常处理相关的代码进行处理的。具体是什么样的还需要参考源码,但我太懒了不想看233出现异常的原因是因为,使用 @app.errorhandler(404) 修饰后会向page_not_found传递一个参数,该参数是抛出的异常werkzeug.exceptions.NotFound,你需要用一个参数去接收它,否则抛出异常 TypeError: page_not_found() takes no arguments (1 given)
报错信息提示很清楚
File "/Users/virtualenvs/full-stack/flask0.3/examples/flaskr/flask.py", line 1266, in handle_exception
TypeError: page_error() takes no arguments (1 given)
page_error() 不需要参数,你传递了一个参数。