add a new feature which supports adding middlewares to specific handlers

This commit is contained in:
PandaFeeder 2017-05-13 18:11:34 +08:00
parent ef465fb5fe
commit 3060dd2237

View File

@ -3,7 +3,7 @@ import logging.config
import re
import warnings
from asyncio import get_event_loop, ensure_future, CancelledError
from collections import deque, defaultdict
from collections import deque, defaultdict, Iterable
from functools import partial
from inspect import isawaitable, stack, getmodulename
from traceback import format_exc
@ -12,7 +12,7 @@ from ssl import create_default_context, Purpose
from sanic.config import Config, LOGGING
from sanic.constants import HTTP_METHODS
from sanic.exceptions import ServerError, URLBuildError, SanicException
from sanic.exceptions import ServerError, URLBuildError, SanicException, MiddlewareTypeError
from sanic.handlers import ErrorHandler
from sanic.log import log
from sanic.response import HTTPResponse, StreamingHTTPResponse
@ -110,7 +110,7 @@ class Sanic:
# Decorator
def route(self, uri, methods=frozenset({'GET'}), host=None,
strict_slashes=False):
strict_slashes=False, middleware=None):
"""Decorate a function to be registered as a route
:param uri: path of the URL
@ -125,6 +125,21 @@ class Sanic:
uri = '/' + uri
def response(handler):
# attach middleware to specific handler
if middleware:
for r in ('request', 'response'):
mid = middleware[r]
if mid:
if callable(mid):
vars(handler)["_"+r+"_middleware"] = mid,
elif isinstance(mid, Iterable):
vars(handler)['_'+r+'_middleware'] = tuple(mid)
else:
raise MiddlewareTypeError(
"Middleware mounted on a handler should "
"be a function or a sequence of functions"
)
self.router.add(uri=uri, methods=methods, handler=handler,
host=host, strict_slashes=strict_slashes)
return handler
@ -451,12 +466,9 @@ class Sanic:
request.app = self
response = await self._run_request_middleware(request)
# No middleware results
if not response:
# -------------------------------------------- #
# Execute Handler
# -------------------------------------------- #
# Fetch handler from router
handler, args, kwargs, uri = self.router.get(request)
request.uri_template = uri
@ -465,10 +477,30 @@ class Sanic:
("'None' was returned while requesting a "
"handler from the router"))
# Run response handler
response = handler(request, *args, **kwargs)
if isawaitable(response):
response = await response
# request middleware mounted on handler
mounted_request_middleware = handler._request_middleware
if mounted_request_middleware:
response = await self._handle_mounted_request_middleware(
mounted_request_middleware, request, *args, **kwargs
)
# No mounted request middleware result
if not response:
# -------------------------------------------- #
# Execute Handler
# -------------------------------------------- #
# Run response handler
response = handler(request, *args, **kwargs)
if isawaitable(response):
response = await response
# response middleware mounted on handler
mounted_response_middleware = handler._response_middleware
if mounted_response_middleware:
response = await self._handle_mounted_response_middleware(
mounted_response_middleware, request, response, *args, **kwargs
)
except Exception as e:
# -------------------------------------------- #
# Response Generation Failed
@ -624,6 +656,26 @@ class Sanic:
break
return response
async def _handle_mounted_request_middleware(self, middleware, request, *args, **kwargs):
for mid in middleware:
response = mid(request, *args, **kwargs)
if isawaitable(response):
response = await response
if response:
break
return response
async def _handle_mounted_response_middleware(self, middleware, request, response, *args, **kwargs):
for mid in middleware:
_response = mid(request, response, *args, **kwargs)
if isawaitable(_response):
_response = await _response
if _response:
response = _response
break
return response
def _helper(self, host="127.0.0.1", port=8000, debug=False,
ssl=None, sock=None, workers=1, loop=None,
protocol=HttpProtocol, backlog=100, stop_event=None,