0

I would like to achieve this function: if there's no relevent results in route table(404) ,then redirect it to render a custom made 404 template. Is there's any way of implementation in aiohttp? thanks

AdamHommer
  • 657
  • 7
  • 22

2 Answers2

1

This is covered in the tutorial under middlewares: http://demos.aiohttp.org/en/latest/tutorial.html#middlewares

Edit: My changes have been merged, so just check the link above for the most up-to-date best practices.

I've just proposed some improvements to that code, so here's my improved approach:

import aiohttp_jinja2
from aiohttp import web


async def handle_404(request):
    return aiohttp_jinja2.render_template('404.html', request, {})


async def handle_500(request):
    return aiohttp_jinja2.render_template('500.html', request, {})


def create_error_middleware(overrides):
    @web.middleware
    async def error_middleware(request, handler):
        try:
            return await handler(request)
        except web.HTTPException as ex:
            override = overrides.get(ex.status)
            if override:
                resp = await override(request)
                resp.set_status(ex.status)
                return resp

            raise
        except:
            resp = await overrides[500](request)
            resp.set_status(500)
            return resp

    return error_middleware


def setup_middlewares(app):
    error_middleware = create_error_middleware({
        404: handle_404,
        500: handle_500
    })
    app.middlewares.append(error_middleware)
Sam Bull
  • 2,559
  • 1
  • 15
  • 17
0

Middleware not called without router match.

It can be done with custom router

from aiohttp import web, web_urldispatcher


class Router(web.UrlDispatcher):
    async def resolve(self, request):
        res = await super().resolve(request)

        if isinstance(res,web_urldispatcher.MatchInfoError):
            if res.http_exception.status == 404:
                return web_urldispatcher.MatchInfoError(
                    web.HTTPNotFound(
                        text="<html><body>custom 404</body></html>",
                        content_type="text/html")
                    )

        return res

routes = web.RouteTableDef()

@routes.get('/')
async def hello(request):
    return web.Response(text="Hello, world")

app = web.Application(router= Router())
app.add_routes(routes)
web.run_app(app)

I think a better way is to write custom Resource, but it is not well documented.

eri
  • 3,133
  • 1
  • 23
  • 35