mirror of
				https://github.com/django/django.git
				synced 2025-11-03 21:25:09 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			482 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			482 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
==========
 | 
						|
Middleware
 | 
						|
==========
 | 
						|
 | 
						|
.. module:: django.middleware
 | 
						|
   :synopsis: Django's built-in middleware classes.
 | 
						|
 | 
						|
This document explains all middleware components that come with Django. For
 | 
						|
information on how to use them and how to write your own middleware, see
 | 
						|
the :doc:`middleware usage guide </topics/http/middleware>`.
 | 
						|
 | 
						|
Available middleware
 | 
						|
====================
 | 
						|
 | 
						|
Cache middleware
 | 
						|
----------------
 | 
						|
 | 
						|
.. module:: django.middleware.cache
 | 
						|
   :synopsis: Middleware for the site-wide cache.
 | 
						|
 | 
						|
.. class:: UpdateCacheMiddleware
 | 
						|
 | 
						|
.. class:: FetchFromCacheMiddleware
 | 
						|
 | 
						|
Enable the site-wide cache. If these are enabled, each Django-powered page will
 | 
						|
be cached for as long as the :setting:`CACHE_MIDDLEWARE_SECONDS` setting
 | 
						|
defines. See the :doc:`cache documentation </topics/cache>`.
 | 
						|
 | 
						|
"Common" middleware
 | 
						|
-------------------
 | 
						|
 | 
						|
.. module:: django.middleware.common
 | 
						|
   :synopsis: Middleware adding "common" conveniences for perfectionists.
 | 
						|
 | 
						|
.. class:: CommonMiddleware
 | 
						|
 | 
						|
Adds a few conveniences for perfectionists:
 | 
						|
 | 
						|
* Forbids access to user agents in the :setting:`DISALLOWED_USER_AGENTS`
 | 
						|
  setting, which should be a list of compiled regular expression objects.
 | 
						|
 | 
						|
* Performs URL rewriting based on the :setting:`APPEND_SLASH` and
 | 
						|
  :setting:`PREPEND_WWW` settings.
 | 
						|
 | 
						|
  If :setting:`APPEND_SLASH` is ``True`` and the initial URL doesn't end
 | 
						|
  with a slash, and it is not found in the URLconf, then a new URL is
 | 
						|
  formed by appending a slash at the end. If this new URL is found in the
 | 
						|
  URLconf, then Django redirects the request to this new URL. Otherwise,
 | 
						|
  the initial URL is processed as usual.
 | 
						|
 | 
						|
  For example, ``foo.com/bar`` will be redirected to ``foo.com/bar/`` if
 | 
						|
  you don't have a valid URL pattern for ``foo.com/bar`` but *do* have a
 | 
						|
  valid pattern for ``foo.com/bar/``.
 | 
						|
 | 
						|
  If :setting:`PREPEND_WWW` is ``True``, URLs that lack a leading "www."
 | 
						|
  will be redirected to the same URL with a leading "www."
 | 
						|
 | 
						|
  Both of these options are meant to normalize URLs. The philosophy is that
 | 
						|
  each URL should exist in one, and only one, place. Technically a URL
 | 
						|
  ``foo.com/bar`` is distinct from ``foo.com/bar/`` -- a search-engine
 | 
						|
  indexer would treat them as separate URLs -- so it's best practice to
 | 
						|
  normalize URLs.
 | 
						|
 | 
						|
* Sets the ``Content-Length`` header for non-streaming responses.
 | 
						|
 | 
						|
.. attribute:: CommonMiddleware.response_redirect_class
 | 
						|
 | 
						|
Defaults to :class:`~django.http.HttpResponsePermanentRedirect`. Subclass
 | 
						|
``CommonMiddleware`` and override the attribute to customize the redirects
 | 
						|
issued by the middleware.
 | 
						|
 | 
						|
.. class:: BrokenLinkEmailsMiddleware
 | 
						|
 | 
						|
* Sends broken link notification emails to :setting:`MANAGERS` (see
 | 
						|
  :doc:`/howto/error-reporting`).
 | 
						|
 | 
						|
GZip middleware
 | 
						|
---------------
 | 
						|
 | 
						|
.. module:: django.middleware.gzip
 | 
						|
   :synopsis: Middleware to serve GZipped content for performance.
 | 
						|
 | 
						|
.. class:: GZipMiddleware
 | 
						|
 | 
						|
.. warning::
 | 
						|
 | 
						|
    Security researchers recently revealed that when compression techniques
 | 
						|
    (including ``GZipMiddleware``) are used on a website, the site may become
 | 
						|
    exposed to a number of possible attacks. Before using ``GZipMiddleware`` on
 | 
						|
    your site, you should consider very carefully whether you are subject to
 | 
						|
    these attacks. If you're in *any* doubt about whether you're affected, you
 | 
						|
    should avoid using ``GZipMiddleware``. For more details, see the `the BREACH
 | 
						|
    paper (PDF)`_ and `breachattack.com`_.
 | 
						|
 | 
						|
    .. _the BREACH paper (PDF): http://breachattack.com/resources/BREACH%20-%20SSL,%20gone%20in%2030%20seconds.pdf
 | 
						|
    .. _breachattack.com: http://breachattack.com
 | 
						|
 | 
						|
Compresses content for browsers that understand GZip compression (all modern
 | 
						|
browsers).
 | 
						|
 | 
						|
This middleware should be placed before any other middleware that need to
 | 
						|
read or write the response body so that compression happens afterward.
 | 
						|
 | 
						|
It will NOT compress content if any of the following are true:
 | 
						|
 | 
						|
* The content body is less than 200 bytes long.
 | 
						|
 | 
						|
* The response has already set the ``Content-Encoding`` header.
 | 
						|
 | 
						|
* The request (the browser) hasn't sent an ``Accept-Encoding`` header
 | 
						|
  containing ``gzip``.
 | 
						|
 | 
						|
If the response has an ``ETag`` header, the ETag is made weak to comply with
 | 
						|
:rfc:`7232#section-2.1`.
 | 
						|
 | 
						|
You can apply GZip compression to individual views using the
 | 
						|
:func:`~django.views.decorators.gzip.gzip_page()` decorator.
 | 
						|
 | 
						|
Conditional GET middleware
 | 
						|
--------------------------
 | 
						|
 | 
						|
.. module:: django.middleware.http
 | 
						|
   :synopsis: Middleware handling advanced HTTP features.
 | 
						|
 | 
						|
.. class:: ConditionalGetMiddleware
 | 
						|
 | 
						|
Handles conditional GET operations. If the response doesn't have an ``ETag``
 | 
						|
header, the middleware adds one if needed. If the response has an ``ETag`` or
 | 
						|
``Last-Modified`` header, and the request has ``If-None-Match`` or
 | 
						|
``If-Modified-Since``, the response is replaced by an
 | 
						|
:class:`~django.http.HttpResponseNotModified`.
 | 
						|
 | 
						|
Locale middleware
 | 
						|
-----------------
 | 
						|
 | 
						|
.. module:: django.middleware.locale
 | 
						|
   :synopsis: Middleware to enable language selection based on the request.
 | 
						|
 | 
						|
.. class:: LocaleMiddleware
 | 
						|
 | 
						|
Enables language selection based on data from the request. It customizes
 | 
						|
content for each user. See the :doc:`internationalization documentation
 | 
						|
</topics/i18n/translation>`.
 | 
						|
 | 
						|
.. attribute:: LocaleMiddleware.response_redirect_class
 | 
						|
 | 
						|
Defaults to :class:`~django.http.HttpResponseRedirect`. Subclass
 | 
						|
``LocaleMiddleware`` and override the attribute to customize the redirects
 | 
						|
issued by the middleware.
 | 
						|
 | 
						|
Message middleware
 | 
						|
------------------
 | 
						|
 | 
						|
.. module:: django.contrib.messages.middleware
 | 
						|
   :synopsis: Message middleware.
 | 
						|
 | 
						|
.. class:: MessageMiddleware
 | 
						|
 | 
						|
Enables cookie- and session-based message support. See the
 | 
						|
:doc:`messages documentation </ref/contrib/messages>`.
 | 
						|
 | 
						|
.. _security-middleware:
 | 
						|
 | 
						|
Security middleware
 | 
						|
-------------------
 | 
						|
 | 
						|
.. module:: django.middleware.security
 | 
						|
    :synopsis: Security middleware.
 | 
						|
 | 
						|
.. warning::
 | 
						|
    If your deployment situation allows, it's usually a good idea to have your
 | 
						|
    front-end Web server perform the functionality provided by the
 | 
						|
    ``SecurityMiddleware``. That way, if there are requests that aren't served
 | 
						|
    by Django (such as static media or user-uploaded files), they will have
 | 
						|
    the same protections as requests to your Django application.
 | 
						|
 | 
						|
.. class:: SecurityMiddleware
 | 
						|
 | 
						|
The ``django.middleware.security.SecurityMiddleware`` provides several security
 | 
						|
enhancements to the request/response cycle. Each one can be independently
 | 
						|
enabled or disabled with a setting.
 | 
						|
 | 
						|
* :setting:`SECURE_BROWSER_XSS_FILTER`
 | 
						|
* :setting:`SECURE_CONTENT_TYPE_NOSNIFF`
 | 
						|
* :setting:`SECURE_HSTS_INCLUDE_SUBDOMAINS`
 | 
						|
* :setting:`SECURE_HSTS_PRELOAD`
 | 
						|
* :setting:`SECURE_HSTS_SECONDS`
 | 
						|
* :setting:`SECURE_REDIRECT_EXEMPT`
 | 
						|
* :setting:`SECURE_SSL_HOST`
 | 
						|
* :setting:`SECURE_SSL_REDIRECT`
 | 
						|
 | 
						|
.. _http-strict-transport-security:
 | 
						|
 | 
						|
HTTP Strict Transport Security
 | 
						|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
For sites that should only be accessed over HTTPS, you can instruct modern
 | 
						|
browsers to refuse to connect to your domain name via an insecure connection
 | 
						|
(for a given period of time) by setting the `"Strict-Transport-Security"
 | 
						|
header`_. This reduces your exposure to some SSL-stripping man-in-the-middle
 | 
						|
(MITM) attacks.
 | 
						|
 | 
						|
``SecurityMiddleware`` will set this header for you on all HTTPS responses if
 | 
						|
you set the :setting:`SECURE_HSTS_SECONDS` setting to a non-zero integer value.
 | 
						|
 | 
						|
When enabling HSTS, it's a good idea to first use a small value for testing,
 | 
						|
for example, :setting:`SECURE_HSTS_SECONDS = 3600<SECURE_HSTS_SECONDS>` for one
 | 
						|
hour. Each time a Web browser sees the HSTS header from your site, it will
 | 
						|
refuse to communicate non-securely (using HTTP) with your domain for the given
 | 
						|
period of time. Once you confirm that all assets are served securely on your
 | 
						|
site (i.e. HSTS didn't break anything), it's a good idea to increase this value
 | 
						|
so that infrequent visitors will be protected (31536000 seconds, i.e. 1 year,
 | 
						|
is common).
 | 
						|
 | 
						|
Additionally, if you set the :setting:`SECURE_HSTS_INCLUDE_SUBDOMAINS` setting
 | 
						|
to ``True``, ``SecurityMiddleware`` will add the ``includeSubDomains`` directive
 | 
						|
to the ``Strict-Transport-Security`` header. This is recommended (assuming all
 | 
						|
subdomains are served exclusively using HTTPS), otherwise your site may still
 | 
						|
be vulnerable via an insecure connection to a subdomain.
 | 
						|
 | 
						|
If you wish to submit your site to the `browser preload list`_, set the
 | 
						|
:setting:`SECURE_HSTS_PRELOAD` setting to ``True``. That appends the
 | 
						|
``preload`` directive to the ``Strict-Transport-Security`` header.
 | 
						|
 | 
						|
.. warning::
 | 
						|
    The HSTS policy applies to your entire domain, not just the URL of the
 | 
						|
    response that you set the header on. Therefore, you should only use it if
 | 
						|
    your entire domain is served via HTTPS only.
 | 
						|
 | 
						|
    Browsers properly respecting the HSTS header will refuse to allow users to
 | 
						|
    bypass warnings and connect to a site with an expired, self-signed, or
 | 
						|
    otherwise invalid SSL certificate. If you use HSTS, make sure your
 | 
						|
    certificates are in good shape and stay that way!
 | 
						|
 | 
						|
.. note::
 | 
						|
    If you are deployed behind a load-balancer or reverse-proxy server, and the
 | 
						|
    ``Strict-Transport-Security`` header is not being added to your responses,
 | 
						|
    it may be because Django doesn't realize that it's on a secure connection;
 | 
						|
    you may need to set the :setting:`SECURE_PROXY_SSL_HEADER` setting.
 | 
						|
 | 
						|
.. _"Strict-Transport-Security" header: https://en.wikipedia.org/wiki/Strict_Transport_Security
 | 
						|
.. _browser preload list: https://hstspreload.org/
 | 
						|
 | 
						|
.. _x-content-type-options:
 | 
						|
 | 
						|
``X-Content-Type-Options: nosniff``
 | 
						|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
Some browsers will try to guess the content types of the assets that they
 | 
						|
fetch, overriding the ``Content-Type`` header. While this can help display
 | 
						|
sites with improperly configured servers, it can also pose a security
 | 
						|
risk.
 | 
						|
 | 
						|
If your site serves user-uploaded files, a malicious user could upload a
 | 
						|
specially-crafted file that would be interpreted as HTML or JavaScript by
 | 
						|
the browser when you expected it to be something harmless.
 | 
						|
 | 
						|
To prevent the browser from guessing the content type and force it to
 | 
						|
always use the type provided in the ``Content-Type`` header, you can pass
 | 
						|
the `X-Content-Type-Options: nosniff`__ header.  ``SecurityMiddleware`` will
 | 
						|
do this for all responses if the :setting:`SECURE_CONTENT_TYPE_NOSNIFF` setting
 | 
						|
is ``True``.
 | 
						|
 | 
						|
Note that in most deployment situations where Django isn't involved in serving
 | 
						|
user-uploaded files, this setting won't help you. For example, if your
 | 
						|
:setting:`MEDIA_URL` is served directly by your front-end Web server (nginx,
 | 
						|
Apache, etc.) then you'd want to set this header there. On the other hand, if
 | 
						|
you are using Django to do something like require authorization in order to
 | 
						|
download files and you cannot set the header using your Web server, this
 | 
						|
setting will be useful.
 | 
						|
 | 
						|
__ https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
 | 
						|
 | 
						|
.. _x-xss-protection:
 | 
						|
 | 
						|
``X-XSS-Protection: 1; mode=block``
 | 
						|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
Some browsers have the ability to block content that appears to be an `XSS
 | 
						|
attack`_. They work by looking for JavaScript content in the GET or POST
 | 
						|
parameters of a page. If the JavaScript is replayed in the server's response,
 | 
						|
the page is blocked from rendering and an error page is shown instead.
 | 
						|
 | 
						|
The `X-XSS-Protection header`_ is used to control the operation of the
 | 
						|
XSS filter.
 | 
						|
 | 
						|
To enable the XSS filter in the browser, and force it to always block
 | 
						|
suspected XSS attacks, you can pass the ``X-XSS-Protection: 1; mode=block``
 | 
						|
header. ``SecurityMiddleware`` will do this for all responses if the
 | 
						|
:setting:`SECURE_BROWSER_XSS_FILTER` setting is ``True``.
 | 
						|
 | 
						|
.. warning::
 | 
						|
    The browser XSS filter is a useful defense measure, but must not be
 | 
						|
    relied upon exclusively. It cannot detect all XSS attacks and not all
 | 
						|
    browsers support the header. Ensure you are still :ref:`validating and
 | 
						|
    sanitizing <cross-site-scripting>` all input to prevent XSS attacks.
 | 
						|
 | 
						|
.. _XSS attack: https://en.wikipedia.org/wiki/Cross-site_scripting
 | 
						|
.. _X-XSS-Protection header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
 | 
						|
 | 
						|
.. _ssl-redirect:
 | 
						|
 | 
						|
SSL Redirect
 | 
						|
~~~~~~~~~~~~
 | 
						|
 | 
						|
If your site offers both HTTP and HTTPS connections, most users will end up
 | 
						|
with an unsecured connection by default. For best security, you should redirect
 | 
						|
all HTTP connections to HTTPS.
 | 
						|
 | 
						|
If you set the :setting:`SECURE_SSL_REDIRECT` setting to True,
 | 
						|
``SecurityMiddleware`` will permanently (HTTP 301) redirect all HTTP
 | 
						|
connections to HTTPS.
 | 
						|
 | 
						|
.. note::
 | 
						|
 | 
						|
    For performance reasons, it's preferable to do these redirects outside of
 | 
						|
    Django, in a front-end load balancer or reverse-proxy server such as
 | 
						|
    `nginx`_. :setting:`SECURE_SSL_REDIRECT` is intended for the deployment
 | 
						|
    situations where this isn't an option.
 | 
						|
 | 
						|
If the :setting:`SECURE_SSL_HOST` setting has a value, all redirects will be
 | 
						|
sent to that host instead of the originally-requested host.
 | 
						|
 | 
						|
If there are a few pages on your site that should be available over HTTP, and
 | 
						|
not redirected to HTTPS, you can list regular expressions to match those URLs
 | 
						|
in the :setting:`SECURE_REDIRECT_EXEMPT` setting.
 | 
						|
 | 
						|
.. note::
 | 
						|
    If you are deployed behind a load-balancer or reverse-proxy server and
 | 
						|
    Django can't seem to tell when a request actually is already secure, you
 | 
						|
    may need to set the :setting:`SECURE_PROXY_SSL_HEADER` setting.
 | 
						|
 | 
						|
.. _nginx: https://nginx.org
 | 
						|
 | 
						|
Session middleware
 | 
						|
------------------
 | 
						|
 | 
						|
.. module:: django.contrib.sessions.middleware
 | 
						|
   :synopsis: Session middleware.
 | 
						|
 | 
						|
.. class:: SessionMiddleware
 | 
						|
 | 
						|
Enables session support. See the :doc:`session documentation
 | 
						|
</topics/http/sessions>`.
 | 
						|
 | 
						|
Site middleware
 | 
						|
---------------
 | 
						|
 | 
						|
.. module:: django.contrib.sites.middleware
 | 
						|
  :synopsis: Site middleware.
 | 
						|
 | 
						|
.. class:: CurrentSiteMiddleware
 | 
						|
 | 
						|
Adds the ``site`` attribute representing the current site to every incoming
 | 
						|
``HttpRequest`` object. See the :ref:`sites documentation <site-middleware>`.
 | 
						|
 | 
						|
Authentication middleware
 | 
						|
-------------------------
 | 
						|
 | 
						|
.. module:: django.contrib.auth.middleware
 | 
						|
  :synopsis: Authentication middleware.
 | 
						|
 | 
						|
.. class:: AuthenticationMiddleware
 | 
						|
 | 
						|
Adds the ``user`` attribute, representing the currently-logged-in user, to
 | 
						|
every incoming ``HttpRequest`` object. See :ref:`Authentication in Web requests
 | 
						|
<auth-web-requests>`.
 | 
						|
 | 
						|
.. class:: RemoteUserMiddleware
 | 
						|
 | 
						|
Middleware for utilizing Web server provided authentication. See
 | 
						|
:doc:`/howto/auth-remote-user` for usage details.
 | 
						|
 | 
						|
.. class:: PersistentRemoteUserMiddleware
 | 
						|
 | 
						|
Middleware for utilizing Web server provided authentication when enabled only
 | 
						|
on the login page. See :ref:`persistent-remote-user-middleware-howto` for usage
 | 
						|
details.
 | 
						|
 | 
						|
CSRF protection middleware
 | 
						|
--------------------------
 | 
						|
 | 
						|
.. currentmodule:: django.middleware.csrf
 | 
						|
 | 
						|
.. class:: CsrfViewMiddleware
 | 
						|
 | 
						|
Adds protection against Cross Site Request Forgeries by adding hidden form
 | 
						|
fields to POST forms and checking requests for the correct value. See the
 | 
						|
:doc:`Cross Site Request Forgery protection documentation </ref/csrf>`.
 | 
						|
 | 
						|
``X-Frame-Options`` middleware
 | 
						|
------------------------------
 | 
						|
 | 
						|
.. currentmodule:: django.middleware.clickjacking
 | 
						|
 | 
						|
.. class:: XFrameOptionsMiddleware
 | 
						|
 | 
						|
Simple :doc:`clickjacking protection via the X-Frame-Options header </ref/clickjacking/>`.
 | 
						|
 | 
						|
.. _middleware-ordering:
 | 
						|
 | 
						|
Middleware ordering
 | 
						|
===================
 | 
						|
 | 
						|
Here are some hints about the ordering of various Django middleware classes:
 | 
						|
 | 
						|
#. :class:`~django.middleware.security.SecurityMiddleware`
 | 
						|
 | 
						|
   It should go near the top of the list if you're going to turn on the SSL
 | 
						|
   redirect as that avoids running through a bunch of other unnecessary
 | 
						|
   middleware.
 | 
						|
 | 
						|
#. :class:`~django.middleware.cache.UpdateCacheMiddleware`
 | 
						|
 | 
						|
   Before those that modify the ``Vary`` header (``SessionMiddleware``,
 | 
						|
   ``GZipMiddleware``, ``LocaleMiddleware``).
 | 
						|
 | 
						|
#. :class:`~django.middleware.gzip.GZipMiddleware`
 | 
						|
 | 
						|
   Before any middleware that may change or use the response body.
 | 
						|
 | 
						|
   After ``UpdateCacheMiddleware``: Modifies ``Vary`` header.
 | 
						|
 | 
						|
#. :class:`~django.contrib.sessions.middleware.SessionMiddleware`
 | 
						|
 | 
						|
   Before any middleware that may raise an an exception to trigger an error
 | 
						|
   view (such as :exc:`~django.core.exceptions.PermissionDenied`) if you're
 | 
						|
   using :setting:`CSRF_USE_SESSIONS`.
 | 
						|
 | 
						|
   After ``UpdateCacheMiddleware``: Modifies ``Vary`` header.
 | 
						|
 | 
						|
#. :class:`~django.middleware.http.ConditionalGetMiddleware`
 | 
						|
 | 
						|
   Before any middleware that may change the response (it sets the ``ETag``
 | 
						|
   header).
 | 
						|
 | 
						|
   After ``GZipMiddleware`` so it won't calculate an ``ETag`` header on gzipped
 | 
						|
   contents.
 | 
						|
 | 
						|
#. :class:`~django.middleware.locale.LocaleMiddleware`
 | 
						|
 | 
						|
   One of the topmost, after ``SessionMiddleware`` (uses session data) and
 | 
						|
   ``UpdateCacheMiddleware`` (modifies ``Vary`` header).
 | 
						|
 | 
						|
#. :class:`~django.middleware.common.CommonMiddleware`
 | 
						|
 | 
						|
   Before any middleware that may change the response (it sets the
 | 
						|
   ``Content-Length`` header). A middleware that appears before
 | 
						|
   ``CommonMiddleware`` and changes the response must reset ``Content-Length``.
 | 
						|
 | 
						|
   Close to the top: it redirects when :setting:`APPEND_SLASH` or
 | 
						|
   :setting:`PREPEND_WWW` are set to ``True``.
 | 
						|
 | 
						|
   After ``SessionMiddleware`` if you're using :setting:`CSRF_USE_SESSIONS`.
 | 
						|
 | 
						|
#. :class:`~django.middleware.csrf.CsrfViewMiddleware`
 | 
						|
 | 
						|
   Before any view middleware that assumes that CSRF attacks have been dealt
 | 
						|
   with.
 | 
						|
 | 
						|
   After ``SessionMiddleware`` if you're using :setting:`CSRF_USE_SESSIONS`.
 | 
						|
 | 
						|
#. :class:`~django.contrib.auth.middleware.AuthenticationMiddleware`
 | 
						|
 | 
						|
   After ``SessionMiddleware``: uses session storage.
 | 
						|
 | 
						|
#. :class:`~django.contrib.messages.middleware.MessageMiddleware`
 | 
						|
 | 
						|
   After ``SessionMiddleware``: can use session-based storage.
 | 
						|
 | 
						|
#. :class:`~django.middleware.cache.FetchFromCacheMiddleware`
 | 
						|
 | 
						|
   After any middleware that modifies the ``Vary`` header: that header is used
 | 
						|
   to pick a value for the cache hash-key.
 | 
						|
 | 
						|
#. :class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware`
 | 
						|
 | 
						|
   Should be near the bottom as it's a last-resort type of middleware.
 | 
						|
 | 
						|
#. :class:`~django.contrib.redirects.middleware.RedirectFallbackMiddleware`
 | 
						|
 | 
						|
   Should be near the bottom as it's a last-resort type of middleware.
 |