
Вспомнил о своем аккаунте на Google App Engine, промелькнула мысль "Можно же построить свой CDN, практически без затрат денег и управлять им так, как душа пожелает". Реализации, которые есть на текущий момент меня немного не устроили и работа закипела.
В качестве основы был выбран webapp фреймворк. Но речь как раз не о моей реализации, а о тонкостях самого фреймворка. Краткий пост хотел посвятить небольшому хаку по обработке запросов, в которых произошла ошибка.
В документации данная тема раскрыта в статье "Перенаправления, заголовки и коды статуса". И приведен следующий пример.
Вроде бы все понятно, если вызвать self.error(500), то все данные которые записаны в ответ будут удалены и будет возвращено сообщение об ошибке.
class MyHandler(webapp.RequestHandler):
def get(self):
self.response.out.write("Вы попросили что-то сделать.")
try:
doSomething()
self.response.out.write("Это сделано!")
except Error:
# Очистить вывод и вернуть сообщение об ошибке.
self.error(500)
Но при выполнении сразу можно заметить один маленький нюанс, сервер нам вернет пустую страницу в случае, когда отработает команда self.error(500) или self.error(404), или будет вызван данный метод с любой другой ошибкой. Но как и написано в документации, ответ будет имеет код ошибки 500 или 404, или любой другой, соответственно.
Поведение метода можно посмотреть в исходниках.
google.appengine.ext.webapp.RequestHandler
Он всего лишь устанавливает нужный статус и очищает ответ. А хотелось же получить страницу с сообщением об ошибке :(!!!
class Request(webob.Request):
...
def error(self, code):
"""Clears the response output stream and sets the given HTTP error code.
Args:
code: the HTTP status error code (e.g., 501)
"""
self.response.set_status(code)
self.response.clear()
...
Просто редиректить на страницу ошибки как-то не интересно. Добавлять после каждого вызова "self.error" рендер страницы ошибки тоже как-то не кошерно. Решил добавить небольшой хак
import os
import logging
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp import RequestHandler
template_path = os.path.join(os.path.dirname(__file__), "templates")
def get_template_path(file_name):
return os.path.join(template_path, file_name)
def error_decorator(func):
def wrapper(*args, **kwarg):
handler = args[0]
status_code = args[1]
result = func(*args, **kwarg)
try:
html = {
404 : "404.html",
500 : "500.html"
}[status_code]
if not html:
return;
handler.response.out.write(template.render(get_template_path(html), template_values))
except Exception, e:
logging.error('Raise error in error_decorator. %s' % e)
return result
return wrapper
def main():
RequestHandler.error = error_decorator(RequestHandler.error)
application = webapp.WSGIApplication(
[('/', MainHandler),
], debug=True)
util.run_wsgi_app(application)
if __name__ == '__main__':
main()
При вызове метода "self.error(404)" кроме установки статуса и очистки данных response в ответ будет добавлена страница с сообщением об ошибке. Такой подход имеет ряд преимуществ.
Пользуйтесь! :)
0 коммент.:
Отправить комментарий