Requests
Starlette contains an Request class that gives you a friendlier interface to handle incoming requests rather than direct access to ASGI scopes and receive channels.
request
Signed by: Request(scope, receive=None)
from starlette.requests import Request
from starlette.responses import Response
async def app(scope, receive, send):
assert scope['type'] == 'http'
request = Request(scope, receive)
content = '%s %s' % (request.method, request.url.path)
response = Response(content, media_type='text/plain')
await response(scope, receive, send)
Requests provide a mapping interface, so you can use them just as you would scope.
For example:request['path'] will return the ASGI path.
If you do not need access to the request body, you can instantiate the request without supplying parameters to receive.
method
The request method is accessed as request.method.
Uniform Resource Locator (also commonly referred to simply as URL)
The requested URL/request.url.html was not found on this server.
This property is a string-like object that exposes all components that can be parsed from the URL.
For example:request.url.path,request.url.port,request.url.scheme.
headline
The header is exposed as an immutable, case-insensitive multidictionary.
For example: request.headers['content-type']
query parameter
Query parameters are exposed as immutable multiple dictionaries.
For example: request.query_params['search']
path parameters
Router path parameters are exposed as dictionary interfaces.
For example: request.path_params['username']
customer address
The client's remote address is exposed as a binary called request.client (or None )。
The hostname or IP address: request.client.host
Port number the client is connecting to: request.client.port
Cookies
Cookies are presented in the form of regular dictionary interfaces.
For example: request.cookies.get('mycookie')
Cookies are ignored in case of invalid cookies.(RFC2109)
body
There are several different interfaces for returning the body of the request:
Request body in bytes: await request.body()
Request body, parsed into form data or multipart: async with request.form() as form:
Request body, parsed to JSON: await request.json()
You can also access the request body as a stream using async for syntax:
from starlette.requests import Request
from starlette.responses import Response
async def app(scope, receive, send):
assert scope['type'] == 'http'
request = Request(scope, receive)
body = b''
async for chunk in request.stream():
body += chunk
response = Response(body, media_type='text/plain')
await response(scope, receive, send)
If you access .stream(), a byte chunk is provided instead of storing the entire body in memory. Any subsequent calls to .body(),.form(), or .json() will raise an error.
In some cases, such as long polling or streaming responses, you may need to determine if the client has disconnected. You can determine this status using disconnected = await request.is_disconnected().
request file
Request files are usually sent as multipart form data (multipart/form-data).
Signed by: request.form(max_files=1000, max_fields=1000)
You can configure the maximum number of fields or files using the parameters max_files and max_fields:
async with request.form(max_files=1000, max_fields=1000):
...
The!!! message sets these limits for security reasons, and allowing an unlimited number of fields or files can lead to denial of service attacks because parsing too many empty fields consumes a lot of CPU and memory.
When you call async with request.form() as form, you receive an starlette.datastructures.FormData, which is an immutable multidictionary containing file uploads and text input. File uploads are represented as instances of starlette.datastructures.UploadFile.
UploadFile Has the following attributes:
filename:strwith the original filename uploaded, orNoneif unavailable (e.g.myimage.jpg).content_type:strwith content type (MIME type/media type) orNoneif unavailable (e.g.image/jpeg).file: anSpooledTemporaryFile(a file-like object). This is the actual Python file, which you can pass directly to other functions or libraries expecting a "file-like" object.headers: anHeadersobject. Usually this will just be theContent-Typeheader, but if other headers are included in the multipart field, they will be included here as well. Note that these headers have nothing to do with the headers inRequest.headers.size: anintof the upload file size in bytes. This value is calculated based on the content of the request and is therefore a better choice for determining the upload file size than theContent-Lengthheader. If not set,None.
UploadFile has the following async methods. They all call the corresponding file methods at the bottom (using the internal SpooledTemporaryFile).
async write(data): writesdata(bytes) to a file.async read(size): Read the file'ssize(int) byte.async seek(offset): Go to byte positionoffset(int) in the file.- For example,
await myfile.seek(0)goes to the beginning of the file.
- For example,
async close(): Close the file.
Since all of these methods are async methods, you need to "wait" for them.
For example, you can get the file name and content by:
async with request.form() as form:
filename = form["upload_file"].filename
contents = await form["upload_file"].read()
!!! information As specified in RFC - 7578: 4.2, the form data content section containing the file assumes name and filename fields in the Content-Disposition header:Content-Disposition: form-data; name="user"; filename="somefile". Although the filename field is optional according to RFC - 7578, it helps Starlette distinguish what data should be considered a file. If the filename field is provided, an UploadFile object is created to access the underlying file, otherwise the form data portion is parsed and available as the original string.
application program
The Starlette application is accessible via request.app.
state
If you want to store additional information on the request, you can do so using request.state.
For example:
request.state.time_started = time.time()