============================ 请求和响应对象 ============================ .. module:: django.http :synopsis: Classes dealing with HTTP requests and responses. 概述 ============== Django使用Request对象和Response对象在系统间传递状态. 当请求一个页面时, Django会创建一个包含请求元数据的 :class:`HttpRequest` 对象. 然后加载相应的视图, 将 :class:`HttpRequest` 作为视图函数的第一个参数传入. 视图函数负责返回一个 :class:`HttpResponse` 对象. 本文档对 :class:`HttpRequest` 和 :class:`HttpResponse` 对象的API进行说明, 这些API定义在 :mod:`django.http` 模块中. ``HttpRequest`` 对象 ======================= .. class:: HttpRequest .. _httprequest-attributes: 属性 ---------- 除非另有说明, 否则所有属性都应视为只读. .. attribute:: HttpRequest.scheme 代表请求协议的字符串 (通常是 ``http`` 或 ``https``). .. attribute:: HttpRequest.body 表示原始HTTP请求正文的字节字符串. 它对处理非HTML表单数据非常有用: 二进制图片, XML等. 如果要处理常规表单数据, 请使用 ``HttpRequest.POST``. 还可以使用类似文件的接口从HttpRequest读取数据. 详见 :meth:`HttpRequest.read()`. .. attribute:: HttpRequest.path 请求页面完整路径, 不包括scheme和domain. 例如: ``"/music/bands/the_beatles/"`` .. attribute:: HttpRequest.path_info 在某些Web服务器配置下, 主机名后的URL被分成脚本前缀部分和路径信息部分. ``path_info`` 属性始终会包含路径信息部分, 不论使用什么Web服务器, 使用它代替 :attr:`~HttpRequest.path` 可以使代码在测试和开发环境中更好地切换. 例如, 如果应用的 ``WSGIScriptAlias`` 设置为 ``"/minfo"``, ``path`` 是 ``"/minfo/music/bands/the_beatles/"`` 时 ``path_info`` 是 ``"/music/bands/the_beatles/"``. .. attribute:: HttpRequest.method 一个字符串, 表示请求使用的HTTP方法. 大些字母形式. 例如:: if request.method == 'GET': do_something() elif request.method == 'POST': do_something_else() .. attribute:: HttpRequest.encoding 一个字符串, 表示提交的数据的编码(如果为 ``None``, 表示使用 :setting:`DEFAULT_CHARSET` 设置). 可以修改这个属性值来改变访问表单数据使用的编码. 修改后的属性访问(从 ``GET`` 或 ``POST`` 读取)都将使用新的 ``encoding`` 值. 这对于访问数据不是 :setting:`DEFAULT_CHARSET` 编码时非常有用. .. attribute:: HttpRequest.content_type .. versionadded:: 1.10 从 ``CONTENT_TYPE`` 请求头中解析到的MIME类型字符串. .. attribute:: HttpRequest.content_params .. versionadded:: 1.10 ``CONTENT_TYPE`` 请求头中的键值参数字典. .. attribute:: HttpRequest.GET 包含所有HTTP GET请求参数的类字典对象. 详见 :class:`QueryDict`. .. attribute:: HttpRequest.POST 包含所有HTTP POST请求参数的类字典对象, 前提是请求包含了表单数据. 详见 :class:`QueryDict`. 如果需要访问post提交的原始或非表单数据, 可以使用 :attr:`HttpRequest.body` 属性. 有可能会有POST请求但是 ``POST`` 为空字典的情况 -- 比如, 不包含表单数据的POST请求. 因此, 不要使用 ``if request.POST`` 来判断是否为POST请求; 应该使用 ``if request.method == "POST"`` (见上文). 注意: ``POST`` **不** 包含文件上传信息. 见 ``FILES``. .. attribute:: HttpRequest.COOKIES 包含所有cookie的Python字典. 键和值都是字符串. .. attribute:: HttpRequest.FILES 包含所有上传文件的类字典对象. ``FILES`` 中的键为 ```` 中的 ``name``. ``FILES`` 中的值是一个 :class:`~django.core.files.uploadedfile.UploadedFile` 对象. 详见 :doc:`/topics/files`. 注意, 只有 ``
`` 中带有 ``enctype="multipart/form-data"`` 的POST请求, ``FILES`` 才会有数据, 否则将是一个空的类字典对象. .. attribute:: HttpRequest.META 包含所有可用HTTP首部的Python字典. 可用的首部取决了客户端和服务端, 下面是一些例子: * ``CONTENT_LENGTH`` -- 请求体的长度 (字符串). * ``CONTENT_TYPE`` -- 请求体的 MIME 类型. * ``HTTP_ACCEPT`` -- 可接受的响应类型. * ``HTTP_ACCEPT_ENCODING`` -- 可接受的响应编码. * ``HTTP_ACCEPT_LANGUAGE`` -- 可接受的响应语言. * ``HTTP_HOST`` -- 客户端发送的HTTP HOST首部. * ``HTTP_REFERER`` -- referrer页面, 如果有的话. * ``HTTP_USER_AGENT`` -- 客户端的user-agent字符串. * ``QUERY_STRING`` -- 查询字符串, 单独(未解析)的一个字符串. * ``REMOTE_ADDR`` -- 客户端的IP地址. * ``REMOTE_HOST`` -- 客户端的hostname. * ``REMOTE_USER`` -- Web服务器认证的用户, 如果有的话. * ``REQUEST_METHOD`` -- ``"GET"`` 或 ``"POST"`` 等字符串. * ``SERVER_NAME`` -- 服务端的hostname. * ``SERVER_PORT`` --服务端的端口(字符串). 从上面可以看出, 除了 ``CONTENT_LENGTH`` 和 ``CONTENT_TYPE`` 之外, 请求中的HTTP首部都会被转换为 ``META`` 中的键, 它将所有字符转换为大写用下划线连接, 并加上 ``HTTP_`` 前缀, 例如名为 ``X-Bender`` 的首部将被映射到 ``META`` 键 ``HTTP_X_BENDER``. 注意, :djadmin:`runserver` 会取消所有名称中带有下划线的请求头, 因此您不会在 ``META`` 中看到它们. 这可以防止基于下划线和破折号之间的歧义的报文欺骗, 这两种符号在WSGI环境变量中都被规范化为下划线. 它与Nginx和apache2.4+等Web服务器的行为相匹配. .. attribute:: HttpRequest.resolver_match 代表解析后URL的 :class:`~django.urls.ResolverMatch` 实例. 该属性只有在URL解析后才会被设置, 因此它在视图中是可用的, 但是在URL解析之前执行的中间件中不可用(不过可以在 :meth:`process_view` 中使用). 应用程序代码设置的属性 ---------------------------------- Django不会自己设置这些属性, 而是由应用程序设置使用它们. .. attribute:: HttpRequest.current_app :ttag:`url` 模板标签使用它的值作为 :func:`~django.urls.reverse()` 的 ``current_app`` 参数. .. attribute:: HttpRequest.urlconf 这将作为当前请求的根URLconf, 覆盖 :setting:`ROOT_URLCONF` 设置. 详见 :ref:`how-django-processes-a-request`. ``urlconf`` 可以设置为 ``None`` 用来重置在之前中间件中所做的修改, 并返回使用 :setting:`ROOT_URLCONF`. .. versionchanged:: 1.9 在之前版本中, 设置 ``urlconf=None`` 会引发 :exc:`~django.core.exceptions.ImproperlyConfigured` 异常. 中间件设置的属性 ---------------------------- Django的contrib应用中的一些中间件会在请求上设置属性. 如果在请求中没有见到这些属性, 请求确保 :setting:`MIDDLEWARE` 中使用了正确的中间件. .. attribute:: HttpRequest.session 出自 :class:`~django.contrib.sessions.middleware.SessionMiddleware`: 一个可读写的代表当前session的类字典对象. .. attribute:: HttpRequest.site 出自 :class:`~django.contrib.sites.middleware.CurrentSiteMiddleware`: :func:`~django.contrib.sites.shortcuts.get_current_site()` 返回的 :class:`~django.contrib.sites.models.Site` 或者 :class:`~django.contrib.sites.requests.RequestSite` 实例, 代表当前站点. .. attribute:: HttpRequest.user 出自 :class:`~django.contrib.auth.middleware.AuthenticationMiddleware`: 代表当前登录用户的 :setting:`AUTH_USER_MODEL` 实例. 如果用户没有登录, ``user`` 会返回 一个 :class:`~django.contrib.auth.models.AnonymousUser` 实例. 可以使用 :attr:`~django.contrib.auth.models.User.is_authenticated` 来区分它们, 例如:: if request.user.is_authenticated: ... # Do something for logged-in users. else: ... # Do something for anonymous users. 方法 ------- .. method:: HttpRequest.get_host() 根据 ``HTTP_X_FORWARDED_HOST`` (如果启用了 :setting:`USE_X_FORWARDED_HOST`) 和 ``HTTP_HOST`` 首部按顺序返回请求原始host. 如果没有提供响应的值, 则使用 ``SERVER_NAME`` 和 ``SERVER_PORT`` 组合, 详见 :pep:`3333`. 例如: ``"127.0.0.1:8000"`` .. note:: 当使用了多重代理时 :meth:`~HttpRequest.get_host()` 方法会失败. 有个解决方法是使用中间件重新代理首部, 例如:: from django.utils.deprecation import MiddlewareMixin class MultipleProxyMiddleware(MiddlewareMixin): FORWARDED_FOR_FIELDS = [ 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED_HOST', 'HTTP_X_FORWARDED_SERVER', ] def process_request(self, request): """ Rewrites the proxy headers so that only the most recent proxy is used. """ for field in self.FORWARDED_FOR_FIELDS: if field in request.META: if ',' in request.META[field]: parts = request.META[field].split(',') request.META[field] = parts[-1].strip() 该中间件应该放在所有依赖 :meth:`~HttpRequest.get_host()` 的中间件之前 -- 例如, :class:`~django.middleware.common.CommonMiddleware` 或者 :class:`~django.middleware.csrf.CsrfViewMiddleware`. .. method:: HttpRequest.get_port() .. versionadded:: 1.9 根据 ``HTTP_X_FORWARDED_PORT`` (如果启用了 :setting:`USE_X_FORWARDED_PORT` 设置) 和 ``SERVER_PORT`` ``META`` 变量, 按顺序返回请求的原始端口. .. method:: HttpRequest.get_full_path() 返回带有查询字符串的 ``path`` (如果有的话). 例如: ``"/music/bands/the_beatles/?print=true"`` .. method:: HttpRequest.build_absolute_uri(location) 返回 ``location`` 的绝对URI. 如果没有则设置为 ``request.get_full_path()``. 如果URI已经是一个绝对的URI则不会修改, 否则, 使用请求中的服务器相关的变量构建绝对URI. 例如: ``"https://example.com/music/bands/the_beatles/?print=true"`` .. note:: 不鼓励在同一站点中混用HTTP和HTTPS, 因此, :meth:`~HttpRequest.build_absolute_uri()` 会始终返回与当前请求相同协议的绝对URI. 如果你想将用户重定向到HTTPS, 最好让Web服务器将所有HTTP请求重定向到HTTPS. .. method:: HttpRequest.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None) 返回签名的cookie值, 如果签名不再有效则引发 ``django.core.signing.BadSignature`` 异常. 如果提供了 ``default`` 参数, 则不会引发异常而是返回default值. 可选参数 ``salt`` 用来提供额外的保护以防止对秘钥的暴力攻击. ``max_age`` 参数用于检查cookie的签名时间戳, 确保不超过 ``max_age`` 秒. 例如:: >>> request.get_signed_cookie('name') 'Tony' >>> request.get_signed_cookie('name', salt='name-salt') 'Tony' # assuming cookie was set using the same salt >>> request.get_signed_cookie('non-existing-cookie') ... KeyError: 'non-existing-cookie' >>> request.get_signed_cookie('non-existing-cookie', False) False >>> request.get_signed_cookie('cookie-that-was-tampered-with') ... BadSignature: ... >>> request.get_signed_cookie('name', max_age=60) ... SignatureExpired: Signature age 1677.3839159 > 60 seconds >>> request.get_signed_cookie('name', False, max_age=60) False 详见 :doc:`加密签名 ` . .. method:: HttpRequest.is_secure() 如果请求是安全的则返回 ``True`` , 即使用HTTPS. .. method:: HttpRequest.is_ajax() 如果请求是通过 ``XMLHttpRequest`` 发起的则返回 ``True``, 方法是检查 ``HTTP_X_REQUESTED_WITH`` 首部中是否包含 ``'XMLHttpRequest'``. 大部分现在的JavaScript库都会发送这个首部. 如果你自定义了XMLHttpRequest调用(浏览器端), 想要 ``is_ajax()`` 正常工作的话需要手动设置这个首部. 如果响应根据是否通过AJAX请求而有所不同, 并且您正在使用某种形式的缓存, 如Django的 :mod:`缓存中间件`, 则应使用 :func:`vary_on_headers('X-Requested-With') ` 来装饰视图以便正确缓存响应. .. method:: HttpRequest.read(size=None) .. method:: HttpRequest.readline() .. method:: HttpRequest.readlines() .. method:: HttpRequest.xreadlines() .. method:: HttpRequest.__iter__() 实现从HttpRequest实例类似文件读取的接口. 这使得可以以流的方式读取请求. 常见的用例是使用迭代解析器处理大型XML负载, 而无需在内存中构建整个XML树. 给定此标准接口, HttpRequest实例可以直接传递给XML解析器, 如ElementTree:: import xml.etree.ElementTree as ET for element in ET.iterparse(request): process(element) ``QueryDict`` 对象 ===================== .. class:: QueryDict 在 :class:`HttpRequest` 对象中, ``GET`` 和 ``POST`` 属性都是 ``django.http.QueryDict`` 实例, 这是一个类似字典的类, 用来处理一个键的多个值. 这很有用, 因为有些HTML表单, 尤其是 ``