forked from orbit-oss/flask
document that headers must be set before streaming
This commit is contained in:
parent
f00ad424ee
commit
a29f88ce6f
4 changed files with 55 additions and 8 deletions
|
|
@ -8,6 +8,21 @@ roundtrip to the filesystem?
|
||||||
|
|
||||||
The answer is by using generators and direct responses.
|
The answer is by using generators and direct responses.
|
||||||
|
|
||||||
|
HTTP Response Behavior
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
**Headers cannot be changed after the streaming response starts.**
|
||||||
|
|
||||||
|
When using streaming, it's important to be aware of the order than an HTTP
|
||||||
|
response is sent. All headers must be sent first, then the body. More headers
|
||||||
|
cannot be sent after the body has begun. Therefore, you must make sure all
|
||||||
|
headers are set before starting the response, outside the generator.
|
||||||
|
|
||||||
|
In particular, if the generator will access ``session``, be sure to do so in the
|
||||||
|
view as well so that the ``Vary: cookie`` header will be set. Do not modify the
|
||||||
|
session in the generator, as the ``Set-Cookie`` header will already be sent.
|
||||||
|
|
||||||
|
|
||||||
Basic Usage
|
Basic Usage
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -225,5 +225,11 @@ functions to make this easier to use.
|
||||||
return stream_template("timeline.html")
|
return stream_template("timeline.html")
|
||||||
|
|
||||||
These functions automatically apply the
|
These functions automatically apply the
|
||||||
:func:`~flask.stream_with_context` wrapper if a request is active, so
|
:func:`~flask.stream_with_context` wrapper if a request is active, so that
|
||||||
that it remains available in the template.
|
:data:`.request`, :data:`.session`, and :data:`.g` remain available in the
|
||||||
|
template.
|
||||||
|
|
||||||
|
More headers cannot be sent after the body has begun. Therefore, you must
|
||||||
|
make sure all headers are set before starting the response. In particular,
|
||||||
|
if the template will access ``session``, be sure to do so in the view as
|
||||||
|
well so that the ``Vary: cookie`` header will be set.
|
||||||
|
|
|
||||||
|
|
@ -153,13 +153,27 @@ F = t.TypeVar("F", bound=t.Callable[..., t.Any])
|
||||||
|
|
||||||
|
|
||||||
def copy_current_request_context(f: F) -> F:
|
def copy_current_request_context(f: F) -> F:
|
||||||
"""A helper function that decorates a function to retain the current
|
"""Decorate a function to run inside the current request context. This can
|
||||||
request context. This is useful when working with greenlets. The moment
|
be used when starting a background task, otherwise it will not see the app
|
||||||
the function is decorated a copy of the request context is created and
|
and request objects that were active in the parent.
|
||||||
then pushed when the function is called. The current session is also
|
|
||||||
included in the copied request context.
|
|
||||||
|
|
||||||
Example::
|
.. warning::
|
||||||
|
|
||||||
|
Due to the following caveats, it is often safer (and simpler) to pass
|
||||||
|
the data you need when starting the task, rather than using this and
|
||||||
|
relying on the context objects.
|
||||||
|
|
||||||
|
In order to avoid execution switching partially though reading data, either
|
||||||
|
read the request body (access ``form``, ``json``, ``data``, etc) before
|
||||||
|
starting the task, or use a lock. This can be an issue when using threading,
|
||||||
|
but shouldn't be an issue when using greenlet/gevent or asyncio.
|
||||||
|
|
||||||
|
If the task will access ``session``, be sure to do so in the parent as well
|
||||||
|
so that the ``Vary: cookie`` header will be set. Modifying ``session`` in
|
||||||
|
the task should be avoided, as it may execute after the response cookie has
|
||||||
|
already been written.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
import gevent
|
import gevent
|
||||||
from flask import copy_current_request_context
|
from flask import copy_current_request_context
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,18 @@ def stream_with_context(
|
||||||
available, even though at the point the generator runs the request context
|
available, even though at the point the generator runs the request context
|
||||||
will typically have ended.
|
will typically have ended.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Due to the following caveat, it is often safer to pass the data you
|
||||||
|
need as arguments to the generator, rather than relying on the context
|
||||||
|
objects.
|
||||||
|
|
||||||
|
More headers cannot be sent after the body has begun. Therefore, you must
|
||||||
|
make sure all headers are set before starting the response. In particular,
|
||||||
|
if the generator will access ``session``, be sure to do so in the view as
|
||||||
|
well so that the ``Vary: cookie`` header will be set. Do not modify the
|
||||||
|
session in the generator, as the ``Set-Cookie`` header will already be sent.
|
||||||
|
|
||||||
Use it as a decorator on a generator function:
|
Use it as a decorator on a generator function:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue