1.. _aiohttp-web-advanced:
2
3Web Server Advanced
4===================
5
6.. currentmodule:: aiohttp.web
7
8
9Unicode support
10---------------
11
12*aiohttp* does :term:`requoting` of incoming request path.
13
14Unicode (non-ASCII) symbols are processed transparently on both *route
15adding* and *resolving* (internally everything is converted to
16:term:`percent-encoding` form by :term:`yarl` library).
17
18But in case of custom regular expressions for
19:ref:`aiohttp-web-variable-handler` please take care that URL is
20*percent encoded*: if you pass Unicode patterns they don't match to
21*requoted* path.
22
23Peer disconnection
24------------------
25
26When a client peer is gone a subsequent reading or writing raises :exc:`OSError`
27or more specific exception like :exc:`ConnectionResetError`.
28
29The reason for disconnection is vary; it can be a network issue or explicit
30socket closing on the peer side without reading the whole server response.
31
32*aiohttp* handles disconnection properly but you can handle it explicitly, e.g.::
33
34   async def handler(request):
35       try:
36           text = await request.text()
37       except OSError:
38           # disconnected
39
40Passing a coroutine into run_app and Gunicorn
41---------------------------------------------
42
43:func:`run_app` accepts either application instance or a coroutine for
44making an application. The coroutine based approach allows to perform
45async IO before making an app::
46
47   async def app_factory():
48       await pre_init()
49       app = web.Application()
50       app.router.add_get(...)
51       return app
52
53   web.run_app(app_factory())
54
55Gunicorn worker supports a factory as well. For Gunicorn the factory
56should accept zero parameters::
57
58   async def my_web_app():
59       app = web.Application()
60       app.router.add_get(...)
61       return app
62
63Start gunicorn:
64
65.. code-block:: shell
66
67   $ gunicorn my_app_module:my_web_app --bind localhost:8080 --worker-class aiohttp.GunicornWebWorker
68
69.. versionadded:: 3.1
70
71Custom Routing Criteria
72-----------------------
73
74Sometimes you need to register :ref:`handlers <aiohttp-web-handler>` on
75more complex criteria than simply a *HTTP method* and *path* pair.
76
77Although :class:`UrlDispatcher` does not support any extra criteria, routing
78based on custom conditions can be accomplished by implementing a second layer
79of routing in your application.
80
81The following example shows custom routing based on the *HTTP Accept* header::
82
83   class AcceptChooser:
84
85       def __init__(self):
86           self._accepts = {}
87
88       async def do_route(self, request):
89           for accept in request.headers.getall('ACCEPT', []):
90               acceptor = self._accepts.get(accept)
91               if acceptor is not None:
92                   return (await acceptor(request))
93           raise HTTPNotAcceptable()
94
95       def reg_acceptor(self, accept, handler):
96           self._accepts[accept] = handler
97
98
99   async def handle_json(request):
100       # do json handling
101
102   async def handle_xml(request):
103       # do xml handling
104
105   chooser = AcceptChooser()
106   app.add_routes([web.get('/', chooser.do_route)])
107
108   chooser.reg_acceptor('application/json', handle_json)
109   chooser.reg_acceptor('application/xml', handle_xml)
110
111.. _aiohttp-web-static-file-handling:
112
113Static file handling
114--------------------
115
116The best way to handle static files (images, JavaScripts, CSS files
117etc.) is using `Reverse Proxy`_ like `nginx`_ or `CDN`_ services.
118
119.. _Reverse Proxy: https://en.wikipedia.org/wiki/Reverse_proxy
120.. _nginx: https://nginx.org/
121.. _CDN: https://en.wikipedia.org/wiki/Content_delivery_network
122
123But for development it's very convenient to handle static files by
124aiohttp server itself.
125
126To do it just register a new static route by
127:meth:`RouteTableDef.static` or :func:`static` calls::
128
129   app.add_routes([web.static('/prefix', path_to_static_folder)])
130
131   routes.static('/prefix', path_to_static_folder)
132
133When a directory is accessed within a static route then the server responses
134to client with ``HTTP/403 Forbidden`` by default. Displaying folder index
135instead could be enabled with ``show_index`` parameter set to ``True``::
136
137   web.static('/prefix', path_to_static_folder, show_index=True)
138
139When a symlink from the static directory is accessed, the server responses to
140client with ``HTTP/404 Not Found`` by default. To allow the server to follow
141symlinks, parameter ``follow_symlinks`` should be set to ``True``::
142
143   web.static('/prefix', path_to_static_folder, follow_symlinks=True)
144
145When you want to enable cache busting,
146parameter ``append_version`` can be set to ``True``
147
148Cache busting is the process of appending some form of file version hash
149to the filename of resources like JavaScript and CSS files.
150The performance advantage of doing this is that we can tell the browser
151to cache these files indefinitely without worrying about the client not getting
152the latest version when the file changes::
153
154   web.static('/prefix', path_to_static_folder, append_version=True)
155
156Template Rendering
157------------------
158
159:mod:`aiohttp.web` does not support template rendering out-of-the-box.
160
161However, there is a third-party library, :mod:`aiohttp_jinja2`, which is
162supported by the *aiohttp* authors.
163
164Using it is rather simple. First, setup a *jinja2 environment* with a call
165to :func:`aiohttp_jinja2.setup`::
166
167    app = web.Application()
168    aiohttp_jinja2.setup(app,
169        loader=jinja2.FileSystemLoader('/path/to/templates/folder'))
170
171After that you may use the template engine in your
172:ref:`handlers <aiohttp-web-handler>`. The most convenient way is to simply
173wrap your handlers with the  :func:`aiohttp_jinja2.template` decorator::
174
175    @aiohttp_jinja2.template('tmpl.jinja2')
176    async def handler(request):
177        return {'name': 'Andrew', 'surname': 'Svetlov'}
178
179If you prefer the `Mako`_ template engine, please take a look at the
180`aiohttp_mako`_ library.
181
182.. warning::
183
184   :func:`aiohttp_jinja2.template` should be applied **before**
185   :meth:`RouteTableDef.get` decorator and family, e.g. it must be
186   the *first* (most *down* decorator in the chain)::
187
188
189      @routes.get('/path')
190      @aiohttp_jinja2.template('tmpl.jinja2')
191      async def handler(request):
192          return {'name': 'Andrew', 'surname': 'Svetlov'}
193
194
195.. _Mako: http://www.makotemplates.org/
196
197.. _aiohttp_mako: https://github.com/aio-libs/aiohttp_mako
198
199
200.. _aiohttp-web-websocket-read-same-task:
201
202Reading from the same task in WebSockets
203----------------------------------------
204
205Reading from the *WebSocket* (``await ws.receive()``) **must only** be
206done inside the request handler *task*; however, writing
207(``ws.send_str(...)``) to the *WebSocket*, closing (``await
208ws.close()``) and canceling the handler task may be delegated to other
209tasks. See also :ref:`FAQ section
210<aiohttp_faq_terminating_websockets>`.
211
212:mod:`aiohttp.web` creates an implicit :class:`asyncio.Task` for
213handling every incoming request.
214
215.. note::
216
217   While :mod:`aiohttp.web` itself only supports *WebSockets* without
218   downgrading to *LONG-POLLING*, etc., our team supports SockJS_, an
219   aiohttp-based library for implementing SockJS-compatible server
220   code.
221
222.. _SockJS: https://github.com/aio-libs/sockjs
223
224
225.. warning::
226
227   Parallel reads from websocket are forbidden, there is no
228   possibility to call :meth:`WebSocketResponse.receive`
229   from two tasks.
230
231   See :ref:`FAQ section <aiohttp_faq_parallel_event_sources>` for
232   instructions how to solve the problem.
233
234
235.. _aiohttp-web-data-sharing:
236
237Data Sharing aka No Singletons Please
238-------------------------------------
239
240:mod:`aiohttp.web` discourages the use of *global variables*, aka *singletons*.
241Every variable should have its own context that is *not global*.
242
243So, :class:`Application` and :class:`Request`
244support a :class:`collections.abc.MutableMapping` interface (i.e. they are
245dict-like objects), allowing them to be used as data stores.
246
247
248.. _aiohttp-web-data-sharing-app-config:
249
250Application's config
251^^^^^^^^^^^^^^^^^^^^
252
253For storing *global-like* variables, feel free to save them in an
254:class:`Application` instance::
255
256    app['my_private_key'] = data
257
258and get it back in the :term:`web-handler`::
259
260    async def handler(request):
261        data = request.app['my_private_key']
262
263In case of :ref:`nested applications
264<aiohttp-web-nested-applications>` the desired lookup strategy could
265be the following:
266
2671. Search the key in the current nested application.
2682. If the key is not found continue searching in the parent application(s).
269
270For this please use :attr:`Request.config_dict` read-only property::
271
272    async def handler(request):
273        data = request.config_dict['my_private_key']
274
275
276Request's storage
277^^^^^^^^^^^^^^^^^
278
279Variables that are only needed for the lifetime of a :class:`Request`, can be
280stored in a :class:`Request`::
281
282    async def handler(request):
283      request['my_private_key'] = "data"
284      ...
285
286This is mostly useful for :ref:`aiohttp-web-middlewares` and
287:ref:`aiohttp-web-signals` handlers to store data for further processing by the
288next handlers in the chain.
289
290Response's storage
291^^^^^^^^^^^^^^^^^^
292
293:class:`StreamResponse` and :class:`Response` objects
294also support :class:`collections.abc.MutableMapping` interface. This is useful
295when you want to share data with signals and middlewares once all the work in
296the handler is done::
297
298    async def handler(request):
299      [ do all the work ]
300      response['my_metric'] = 123
301      return response
302
303
304Naming hint
305^^^^^^^^^^^
306
307To avoid clashing with other *aiohttp* users and third-party libraries, please
308choose a unique key name for storing data.
309
310If your code is published on PyPI, then the project name is most likely unique
311and safe to use as the key.
312Otherwise, something based on your company name/url would be satisfactory (i.e.
313``org.company.app``).
314
315
316.. _aiohttp-web-contextvars:
317
318
319ContextVars support
320-------------------
321
322Starting from Python 3.7 asyncio has :mod:`Context Variables <contextvars>` as a
323context-local storage (a generalization of thread-local concept that works with asyncio
324tasks also).
325
326
327*aiohttp* server supports it in the following way:
328
329* A server inherits the current task's context used when creating it.
330  :func:`aiohttp.web.run_app()` runs a task for handling all underlying jobs running
331  the app, but alternatively :ref:`aiohttp-web-app-runners` can be used.
332
333* Application initialization / finalization events (:attr:`Application.cleanup_ctx`,
334  :attr:`Application.on_startup` and :attr:`Application.on_shutdown`,
335  :attr:`Application.on_cleanup`) are executed inside the same context.
336
337  E.g. all context modifications made on application startup are visible on teardown.
338
339* On every request handling *aiohttp* creates a context copy. :term:`web-handler` has
340  all variables installed on initialization stage. But the context modification made by
341  a handler or middleware is invisible to another HTTP request handling call.
342
343An example of context vars usage::
344
345    from contextvars import ContextVar
346
347    from aiohttp import web
348
349    VAR = ContextVar('VAR', default='default')
350
351
352    async def coro():
353        return VAR.get()
354
355
356    async def handler(request):
357        var = VAR.get()
358        VAR.set('handler')
359        ret = await coro()
360        return web.Response(text='\n'.join([var,
361                                            ret]))
362
363
364    async def on_startup(app):
365        print('on_startup', VAR.get())
366        VAR.set('on_startup')
367
368
369    async def on_cleanup(app):
370        print('on_cleanup', VAR.get())
371        VAR.set('on_cleanup')
372
373
374    async def init():
375        print('init', VAR.get())
376        VAR.set('init')
377        app = web.Application()
378        app.router.add_get('/', handler)
379
380        app.on_startup.append(on_startup)
381        app.on_cleanup.append(on_cleanup)
382        return app
383
384
385    web.run_app(init())
386    print('done', VAR.get())
387
388.. versionadded:: 3.5
389
390
391.. _aiohttp-web-middlewares:
392
393Middlewares
394-----------
395
396:mod:`aiohttp.web` provides a powerful mechanism for customizing
397:ref:`request handlers<aiohttp-web-handler>` via *middlewares*.
398
399A *middleware* is a coroutine that can modify either the request or
400response. For example, here's a simple *middleware* which appends
401``' wink'`` to the response::
402
403    from aiohttp.web import middleware
404
405    @middleware
406    async def middleware(request, handler):
407        resp = await handler(request)
408        resp.text = resp.text + ' wink'
409        return resp
410
411.. note::
412
413   The example won't work with streamed responses or websockets
414
415Every *middleware* should accept two parameters, a :class:`request
416<Request>` instance and a *handler*, and return the response or raise
417an exception. If the exception is not an instance of
418:exc:`HTTPException` it is converted to ``500``
419:exc:`HTTPInternalServerError` after processing the
420middlewares chain.
421
422.. warning::
423
424   Second argument should be named *handler* exactly.
425
426When creating an :class:`Application`, these *middlewares* are passed to
427the keyword-only ``middlewares`` parameter::
428
429   app = web.Application(middlewares=[middleware_1,
430                                      middleware_2])
431
432Internally, a single :ref:`request handler <aiohttp-web-handler>` is constructed
433by applying the middleware chain to the original handler in reverse order,
434and is called by the :class:`RequestHandler` as a regular *handler*.
435
436Since *middlewares* are themselves coroutines, they may perform extra
437``await`` calls when creating a new handler, e.g. call database etc.
438
439*Middlewares* usually call the handler, but they may choose to ignore it,
440e.g. displaying *403 Forbidden page* or raising :exc:`HTTPForbidden` exception
441if the user does not have permissions to access the underlying resource.
442They may also render errors raised by the handler, perform some pre- or
443post-processing like handling *CORS* and so on.
444
445The following code demonstrates middlewares execution order::
446
447   from aiohttp import web
448
449   async def test(request):
450       print('Handler function called')
451       return web.Response(text="Hello")
452
453   @web.middleware
454   async def middleware1(request, handler):
455       print('Middleware 1 called')
456       response = await handler(request)
457       print('Middleware 1 finished')
458       return response
459
460   @web.middleware
461   async def middleware2(request, handler):
462       print('Middleware 2 called')
463       response = await handler(request)
464       print('Middleware 2 finished')
465       return response
466
467
468   app = web.Application(middlewares=[middleware1, middleware2])
469   app.router.add_get('/', test)
470   web.run_app(app)
471
472Produced output::
473
474   Middleware 1 called
475   Middleware 2 called
476   Handler function called
477   Middleware 2 finished
478   Middleware 1 finished
479
480Example
481^^^^^^^
482
483A common use of middlewares is to implement custom error pages.  The following
484example will render 404 errors using a JSON response, as might be appropriate
485a JSON REST service::
486
487    from aiohttp import web
488
489    @web.middleware
490    async def error_middleware(request, handler):
491        try:
492            response = await handler(request)
493            if response.status != 404:
494                return response
495            message = response.message
496        except web.HTTPException as ex:
497            if ex.status != 404:
498                raise
499            message = ex.reason
500        return web.json_response({'error': message})
501
502    app = web.Application(middlewares=[error_middleware])
503
504
505Middleware Factory
506^^^^^^^^^^^^^^^^^^
507
508A *middleware factory* is a function that creates a middleware with passed arguments. For example, here's a trivial *middleware factory*::
509
510    def middleware_factory(text):
511        @middleware
512        async def sample_middleware(request, handler):
513            resp = await handler(request)
514            resp.text = resp.text + text
515            return resp
516        return sample_middleware
517
518Remember that contrary to regular middlewares you need the result of a middleware factory not the function itself. So when passing a middleware factory to an app you actually need to call it::
519
520    app = web.Application(middlewares=[middleware_factory(' wink')])
521
522.. _aiohttp-web-signals:
523
524Signals
525-------
526
527Although :ref:`middlewares <aiohttp-web-middlewares>` can customize
528:ref:`request handlers<aiohttp-web-handler>` before or after a :class:`Response`
529has been prepared, they can't customize a :class:`Response` **while** it's
530being prepared. For this :mod:`aiohttp.web` provides *signals*.
531
532For example, a middleware can only change HTTP headers for *unprepared*
533responses (see :meth:`StreamResponse.prepare`), but sometimes we
534need a hook for changing HTTP headers for streamed responses and WebSockets.
535This can be accomplished by subscribing to the
536:attr:`Application.on_response_prepare` signal, which is called after default
537headers have been computed and directly before headers are sent::
538
539    async def on_prepare(request, response):
540        response.headers['My-Header'] = 'value'
541
542    app.on_response_prepare.append(on_prepare)
543
544
545Additionally, the :attr:`Application.on_startup` and
546:attr:`Application.on_cleanup` signals can be subscribed to for
547application component setup and tear down accordingly.
548
549The following example will properly initialize and dispose an aiopg connection
550engine::
551
552    from aiopg.sa import create_engine
553
554    async def create_aiopg(app):
555        app['pg_engine'] = await create_engine(
556            user='postgre',
557            database='postgre',
558            host='localhost',
559            port=5432,
560            password=''
561        )
562
563    async def dispose_aiopg(app):
564        app['pg_engine'].close()
565        await app['pg_engine'].wait_closed()
566
567    app.on_startup.append(create_aiopg)
568    app.on_cleanup.append(dispose_aiopg)
569
570
571Signal handlers should not return a value but may modify incoming mutable
572parameters.
573
574Signal handlers will be run sequentially, in order they were
575added. All handlers must be asynchronous since *aiohttp* 3.0.
576
577.. _aiohttp-web-cleanup-ctx:
578
579Cleanup Context
580---------------
581
582Bare :attr:`Application.on_startup` / :attr:`Application.on_cleanup`
583pair still has a pitfall: signals handlers are independent on each other.
584
585E.g. we have ``[create_pg, create_redis]`` in *startup* signal and
586``[dispose_pg, dispose_redis]`` in *cleanup*.
587
588If, for example, ``create_pg(app)`` call fails ``create_redis(app)``
589is not called. But on application cleanup both ``dispose_pg(app)`` and
590``dispose_redis(app)`` are still called: *cleanup signal* has no
591knowledge about startup/cleanup pairs and their execution state.
592
593
594The solution is :attr:`Application.cleanup_ctx` usage::
595
596    async def pg_engine(app):
597        app['pg_engine'] = await create_engine(
598            user='postgre',
599            database='postgre',
600            host='localhost',
601            port=5432,
602            password=''
603        )
604        yield
605        app['pg_engine'].close()
606        await app['pg_engine'].wait_closed()
607
608    app.cleanup_ctx.append(pg_engine)
609
610The attribute is a list of *asynchronous generators*, a code *before*
611``yield`` is an initialization stage (called on *startup*), a code
612*after* ``yield`` is executed on *cleanup*. The generator must have only
613one ``yield``.
614
615*aiohttp* guarantees that *cleanup code* is called if and only if
616*startup code* was successfully finished.
617
618Asynchronous generators are supported by Python 3.6+, on Python 3.5
619please use `async_generator <https://pypi.org/project/async_generator/>`_
620library.
621
622.. versionadded:: 3.1
623
624.. _aiohttp-web-nested-applications:
625
626Nested applications
627-------------------
628
629Sub applications are designed for solving the problem of the big
630monolithic code base.
631Let's assume we have a project with own business logic and tools like
632administration panel and debug toolbar.
633
634Administration panel is a separate application by its own nature but all
635toolbar URLs are served by prefix like ``/admin``.
636
637Thus we'll create a totally separate application named ``admin`` and
638connect it to main app with prefix by
639:meth:`Application.add_subapp`::
640
641   admin = web.Application()
642   # setup admin routes, signals and middlewares
643
644   app.add_subapp('/admin/', admin)
645
646Middlewares and signals from ``app`` and ``admin`` are chained.
647
648It means that if URL is ``'/admin/something'`` middlewares from
649``app`` are applied first and ``admin.middlewares`` are the next in
650the call chain.
651
652The same is going for
653:attr:`Application.on_response_prepare` signal -- the
654signal is delivered to both top level ``app`` and ``admin`` if
655processing URL is routed to ``admin`` sub-application.
656
657Common signals like :attr:`Application.on_startup`,
658:attr:`Application.on_shutdown` and
659:attr:`Application.on_cleanup` are delivered to all
660registered sub-applications. The passed parameter is sub-application
661instance, not top-level application.
662
663
664Third level sub-applications can be nested into second level ones --
665there are no limitation for nesting level.
666
667Url reversing for sub-applications should generate urls with proper prefix.
668
669But for getting URL sub-application's router should be used::
670
671   admin = web.Application()
672   admin.add_routes([web.get('/resource', handler, name='name')])
673
674   app.add_subapp('/admin/', admin)
675
676   url = admin.router['name'].url_for()
677
678The generated ``url`` from example will have a value
679``URL('/admin/resource')``.
680
681If main application should do URL reversing for sub-application it could
682use the following explicit technique::
683
684   admin = web.Application()
685   admin.add_routes([web.get('/resource', handler, name='name')])
686
687   app.add_subapp('/admin/', admin)
688   app['admin'] = admin
689
690   async def handler(request):  # main application's handler
691       admin = request.app['admin']
692       url = admin.router['name'].url_for()
693
694.. _aiohttp-web-expect-header:
695
696*Expect* Header
697---------------
698
699:mod:`aiohttp.web` supports *Expect* header. By default it sends
700``HTTP/1.1 100 Continue`` line to client, or raises
701:exc:`HTTPExpectationFailed` if header value is not equal to
702"100-continue". It is possible to specify custom *Expect* header
703handler on per route basis. This handler gets called if *Expect*
704header exist in request after receiving all headers and before
705processing application's :ref:`aiohttp-web-middlewares` and
706route handler. Handler can return *None*, in that case the request
707processing continues as usual. If handler returns an instance of class
708:class:`StreamResponse`, *request handler* uses it as response. Also
709handler can raise a subclass of :exc:`HTTPException`. In this case all
710further processing will not happen and client will receive appropriate
711http response.
712
713.. note::
714    A server that does not understand or is unable to comply with any of the
715    expectation values in the Expect field of a request MUST respond with
716    appropriate error status. The server MUST respond with a 417
717    (Expectation Failed) status if any of the expectations cannot be met or,
718    if there are other problems with the request, some other 4xx status.
719
720    http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.20
721
722If all checks pass, the custom handler *must* write a *HTTP/1.1 100 Continue*
723status code before returning.
724
725The following example shows how to setup a custom handler for the *Expect*
726header::
727
728   async def check_auth(request):
729       if request.version != aiohttp.HttpVersion11:
730           return
731
732       if request.headers.get('EXPECT') != '100-continue':
733           raise HTTPExpectationFailed(text="Unknown Expect: %s" % expect)
734
735       if request.headers.get('AUTHORIZATION') is None:
736           raise HTTPForbidden()
737
738       request.transport.write(b"HTTP/1.1 100 Continue\r\n\r\n")
739
740   async def hello(request):
741       return web.Response(body=b"Hello, world")
742
743   app = web.Application()
744   app.add_routes([web.add_get('/', hello, expect_handler=check_auth)])
745
746.. _aiohttp-web-custom-resource:
747
748Custom resource implementation
749------------------------------
750
751To register custom resource use :meth:`UrlDispatcher.register_resource`.
752Resource instance must implement `AbstractResource` interface.
753
754.. _aiohttp-web-app-runners:
755
756Application runners
757-------------------
758
759:func:`run_app` provides a simple *blocking* API for running an
760:class:`Application`.
761
762For starting the application *asynchronously* or serving on multiple
763HOST/PORT :class:`AppRunner` exists.
764
765The simple startup code for serving HTTP site on ``'localhost'``, port
766``8080`` looks like::
767
768    runner = web.AppRunner(app)
769    await runner.setup()
770    site = web.TCPSite(runner, 'localhost', 8080)
771    await site.start()
772
773    while True:
774        await asyncio.sleep(3600)  # sleep forever
775
776To stop serving call :meth:`AppRunner.cleanup`::
777
778    await runner.cleanup()
779
780.. versionadded:: 3.0
781
782.. _aiohttp-web-graceful-shutdown:
783
784Graceful shutdown
785------------------
786
787Stopping *aiohttp web server* by just closing all connections is not
788always satisfactory.
789
790The problem is: if application supports :term:`websocket`\s or *data
791streaming* it most likely has open connections at server
792shutdown time.
793
794The *library* has no knowledge how to close them gracefully but
795developer can help by registering :attr:`Application.on_shutdown`
796signal handler and call the signal on *web server* closing.
797
798Developer should keep a list of opened connections
799(:class:`Application` is a good candidate).
800
801The following :term:`websocket` snippet shows an example for websocket
802handler::
803
804    from aiohttp import web
805    import weakref
806
807    app = web.Application()
808    app['websockets'] = weakref.WeakSet()
809
810    async def websocket_handler(request):
811        ws = web.WebSocketResponse()
812        await ws.prepare(request)
813
814        request.app['websockets'].add(ws)
815        try:
816            async for msg in ws:
817                ...
818        finally:
819            request.app['websockets'].discard(ws)
820
821        return ws
822
823Signal handler may look like::
824
825    from aiohttp import WSCloseCode
826
827    async def on_shutdown(app):
828        for ws in set(app['websockets']):
829            await ws.close(code=WSCloseCode.GOING_AWAY,
830                           message='Server shutdown')
831
832    app.on_shutdown.append(on_shutdown)
833
834Both :func:`run_app` and :meth:`AppRunner.cleanup` call shutdown
835signal handlers.
836
837.. _aiohttp-web-background-tasks:
838
839Background tasks
840-----------------
841
842Sometimes there's a need to perform some asynchronous operations just
843after application start-up.
844
845Even more, in some sophisticated systems there could be a need to run some
846background tasks in the event loop along with the application's request
847handler. Such as listening to message queue or other network message/event
848sources (e.g. ZeroMQ, Redis Pub/Sub, AMQP, etc.) to react to received messages
849within the application.
850
851For example the background task could listen to ZeroMQ on
852:data:`zmq.SUB` socket, process and forward retrieved messages to
853clients connected via WebSocket that are stored somewhere in the
854application (e.g. in the :obj:`application['websockets']` list).
855
856To run such short and long running background tasks aiohttp provides an
857ability to register :attr:`Application.on_startup` signal handler(s) that
858will run along with the application's request handler.
859
860For example there's a need to run one quick task and two long running
861tasks that will live till the application is alive. The appropriate
862background tasks could be registered as an :attr:`Application.on_startup`
863signal handlers as shown in the example below::
864
865
866  async def listen_to_redis(app):
867      try:
868          sub = await aioredis.create_redis(('localhost', 6379))
869          ch, *_ = await sub.subscribe('news')
870          async for msg in ch.iter(encoding='utf-8'):
871              # Forward message to all connected websockets:
872              for ws in app['websockets']:
873                  ws.send_str('{}: {}'.format(ch.name, msg))
874      except asyncio.CancelledError:
875          pass
876      finally:
877          await sub.unsubscribe(ch.name)
878          await sub.quit()
879
880
881  async def start_background_tasks(app):
882      app['redis_listener'] = asyncio.create_task(listen_to_redis(app))
883
884
885  async def cleanup_background_tasks(app):
886      app['redis_listener'].cancel()
887      await app['redis_listener']
888
889
890  app = web.Application()
891  app.on_startup.append(start_background_tasks)
892  app.on_cleanup.append(cleanup_background_tasks)
893  web.run_app(app)
894
895
896The task :func:`listen_to_redis` will run forever.
897To shut it down correctly :attr:`Application.on_cleanup` signal handler
898may be used to send a cancellation to it.
899
900Handling error pages
901--------------------
902
903Pages like *404 Not Found* and *500 Internal Error* could be handled
904by custom middleware, see :ref:`polls demo <aiohttp-demos-polls-middlewares>`
905for example.
906
907.. _aiohttp-web-forwarded-support:
908
909Deploying behind a Proxy
910------------------------
911
912As discussed in :ref:`aiohttp-deployment` the preferable way is
913deploying *aiohttp* web server behind a *Reverse Proxy Server* like
914:term:`nginx` for production usage.
915
916In this way properties like :attr:`BaseRequest.scheme`
917:attr:`BaseRequest.host` and :attr:`BaseRequest.remote` are
918incorrect.
919
920Real values should be given from proxy server, usually either
921``Forwarded`` or old-fashion ``X-Forwarded-For``,
922``X-Forwarded-Host``, ``X-Forwarded-Proto`` HTTP headers are used.
923
924*aiohttp* does not take *forwarded* headers into account by default
925because it produces *security issue*: HTTP client might add these
926headers too, pushing non-trusted data values.
927
928That's why *aiohttp server* should setup *forwarded* headers in custom
929middleware in tight conjunction with *reverse proxy configuration*.
930
931For changing :attr:`BaseRequest.scheme` :attr:`BaseRequest.host` and
932:attr:`BaseRequest.remote` the middleware might use
933:meth:`BaseRequest.clone`.
934
935.. seealso::
936
937   https://github.com/aio-libs/aiohttp-remotes provides secure helpers
938   for modifying *scheme*, *host* and *remote* attributes according
939   to ``Forwarded`` and ``X-Forwarded-*`` HTTP headers.
940
941Swagger support
942---------------
943
944`aiohttp-swagger <https://github.com/cr0hn/aiohttp-swagger>`_ is a
945library that allow to add Swagger documentation and embed the
946Swagger-UI into your :mod:`aiohttp.web` project.
947
948CORS support
949------------
950
951:mod:`aiohttp.web` itself does not support `Cross-Origin Resource
952Sharing <https://en.wikipedia.org/wiki/Cross-origin_resource_sharing>`_, but
953there is an aiohttp plugin for it:
954`aiohttp_cors <https://github.com/aio-libs/aiohttp_cors>`_.
955
956
957Debug Toolbar
958-------------
959
960`aiohttp-debugtoolbar`_ is a very useful library that provides a
961debugging toolbar while you're developing an :mod:`aiohttp.web`
962application.
963
964Install it with ``pip``:
965
966.. code-block:: shell
967
968    $ pip install aiohttp_debugtoolbar
969
970
971Just call :func:`aiohttp_debugtoolbar.setup`::
972
973    import aiohttp_debugtoolbar
974    from aiohttp_debugtoolbar import toolbar_middleware_factory
975
976    app = web.Application()
977    aiohttp_debugtoolbar.setup(app)
978
979The toolbar is ready to use. Enjoy!!!
980
981.. _aiohttp-debugtoolbar: https://github.com/aio-libs/aiohttp_debugtoolbar
982
983
984Dev Tools
985---------
986
987`aiohttp-devtools`_ provides a couple of tools to simplify development of
988:mod:`aiohttp.web` applications.
989
990
991Install with ``pip``:
992
993.. code-block:: shell
994
995    $ pip install aiohttp-devtools
996
997* ``runserver`` provides a development server with auto-reload,
998  live-reload, static file serving and `aiohttp-debugtoolbar`_
999  integration.
1000* ``start`` is a `cookiecutter command which does the donkey work
1001  of creating new :mod:`aiohttp.web` Applications.
1002
1003Documentation and a complete tutorial of creating and running an app
1004locally are available at `aiohttp-devtools`_.
1005
1006.. _aiohttp-devtools: https://github.com/aio-libs/aiohttp-devtools
1007