Django获取用户请求头部信息
摘要
在我们的Django开发中,有时候会需要用到用户请求头部信息。列举几个简单的例子:
- 获取用户客户端类型
HTTP_USER_AGENT
- 获取用户的出口IP
REMOTE_ADDR
- 获取用户HTTP方式
REQUEST_METHOD
但是如何在Django中获取这些信息呢?
从请求入手
1. Django的请求生命周期
- 用户发出请求,浏览器封装请求头和请求体发给服务端
- 请求经过Django中的wsgi,到达url关系映射表进行匹配
- 只要匹配上其中一条匹配规则就执行对应的视图函数
- 视图函数根据客户端的请求做相应的处理,并将处理结果(字符串)经由模板加工渲染返回给用户
- 用户浏览器进行渲染后呈现给用户
2. request里面到底是什么
我们在某一个视图函数中打印这个request
def index(request):
print(type(request),request)
得到输出如下
<class 'django.core.handlers.wsgi.WSGIRequest'> <WSGIRequest: GET '/index/'>
可见request
是一个类WSGIRequest
的对象,这个类在django.core.handlers.wsgi
中.
去查看这个类,如下:
class WSGIRequest(http.HttpRequest):
def __init__(self, environ):
script_name = get_script_name(environ)
path_info = get_path_info(environ)
if not path_info:
# Sometimes PATH_INFO exists, but is empty (e.g. accessing
# the SCRIPT_NAME URL without a trailing slash). We really need to
# operate as if they'd requested '/'. Not amazingly nice to force
# the path like this, but should be harmless.
path_info = '/'
self.environ = environ
self.path_info = path_info
# be careful to only replace the first slash in the path because of
# http://test/something and http://test//something being different as
# stated in http://www.ietf.org/rfc/rfc2396.txt
self.path = '%s/%s' % (script_name.rstrip('/'),
path_info.replace('/', '', 1))
self.META = environ
self.META['PATH_INFO'] = path_info
self.META['SCRIPT_NAME'] = script_name
self.method = environ['REQUEST_METHOD'].upper()
self.content_type, self.content_params = cgi.parse_header(environ.get('CONTENT_TYPE', ''))
if 'charset' in self.content_params:
try:
codecs.lookup(self.content_params['charset'])
except LookupError:
pass
else:
self.encoding = self.content_params['charset']
self._post_parse_error = False
try:
content_length = int(environ.get('CONTENT_LENGTH'))
except (ValueError, TypeError):
content_length = 0
self._stream = LimitedStream(self.environ['wsgi.input'], content_length)
self._read_started = False
self.resolver_match = None
....
可以看到类中封装了一个属性:
- self.environ
- self.path_info
- self.method
- self.path
- ...
我们依次打印出来这些信息看看:
environ {'PATH': '/Users/qiumeng/.pyenv/versions/3.6.2/bin:/usr/local/Cellar/pyenv/1.1.3/libexec:/Users/qiumeng/.pyenv/shims:/Users/qiumeng/.pyenv/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Applications/Wireshark.app/Contents/MacOS:/Users/qiumeng/GoLang/bin:/usr/local/Cellar/go/1.8.3/libexec/bin', 'PYENV_SHELL': 'bash', 'DISPLAY': '/private/tmp/com.apple.launchd.5ODiXCCeal/org.macosforge.xquartz:0', 'LOGNAME': 'qiumeng', 'PYENV_VERSION': '3.6.2', 'XPC_SERVICE_NAME': 'com.jetbrains.pycharm.8256', 'PWD': '/Users/qiumeng/PycharmProjects/day21', 'PYCHARM_HOSTED': '1', 'PYTHONPATH': '/Users/qiumeng/PycharmProjects/day21', 'SHELL': '/bin/bash', 'PYTHONIOENCODING': 'UTF-8', 'PYENV_DIR': '/Applications/PyCharm.app/Contents/bin', 'PYENV_ROOT': '/Users/qiumeng/.pyenv', 'GOPATH': '/Users/qiumeng/GoLang', 'USER': 'qiumeng', 'GOROOT': '/usr/local/Cellar/go/1.8.3/libexec', 'TMPDIR': '/var/folders/k5/9fcwbxhn1_d_x3lxvs868m6c0000gn/T/', 'PYENV_HOOK_PATH': '/Users/qiumeng/.pyenv/pyenv.d:/usr/local/Cellar/pyenv/1.1.3/pyenv.d:/usr/local/etc/pyenv.d:/etc/pyenv.d:/usr/lib/pyenv/hooks', 'SSH_AUTH_SOCK': '/private/tmp/com.apple.launchd.kT7ERQ3lJ4/Listeners', 'DJANGO_SETTINGS_MODULE': 'day21.settings', 'XPC_FLAGS': '0x0', 'PYTHONUNBUFFERED': '1', '__CF_USER_TEXT_ENCODING': '0x1F5:0x19:0x34', 'Apple_PubSub_Socket_Render': '/private/tmp/com.apple.launchd.nEfmDxko1b/Render', 'LC_CTYPE': 'zh_CN.UTF-8', 'HOME': '/Users/qiumeng', 'TZ': 'UTC', 'RUN_MAIN': 'true', 'SERVER_NAME': '1.0.0.127.in-addr.arpa', 'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_PORT': '8000', 'REMOTE_HOST': '', 'CONTENT_LENGTH': '', 'SCRIPT_NAME': '', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.2', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/index/', 'QUERY_STRING': '', 'REMOTE_ADDR': '127.0.0.1', 'CONTENT_TYPE': 'text/plain', 'HTTP_HOST': '127.0.0.1:8000', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_CACHE_CONTROL': 'max-age=0', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36', 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9', 'HTTP_COOKIE': 'csrftoken=Ne1RJ3duPUV5mFJysr9r48fgEZCaJY75RFsh6ujbELqQYYzxOynhoLSVT3GnUblx', 'wsgi.input': <_io.BufferedReader name=4>, 'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, 'wsgi.version': (1, 0), 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.multithread': True, 'wsgi.multiprocess': False, 'wsgi.file_wrapper': <class 'wsgiref.util.FileWrapper'>}
path_info /index/
method GET
path /index/
3. environ
属性
从上面的environ
中我们看到,我们想要的任何存在的请求头信息是在environ
这个属性中的,我们把它一一列举一下:
def index(request):
print(type(request.environ))
for k,v in request.environ.items():
print(k,v)
结果如下:
PATH /Users/qiumeng/.pyenv/versions/3.6.2/bin:/usr/local/Cellar/pyenv/1.1.3/libexec:/Users/qiumeng/.pyenv/shims:/Users/qiumeng/.pyenv/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Applications/Wireshark.app/Contents/MacOS:/Users/qiumeng/GoLang/bin:/usr/local/Cellar/go/1.8.3/libexec/bin
PYENV_SHELL bash
DISPLAY /private/tmp/com.apple.launchd.5ODiXCCeal/org.macosforge.xquartz:0
LOGNAME qiumeng
PYENV_VERSION 3.6.2
XPC_SERVICE_NAME com.jetbrains.pycharm.8256
PWD /Users/qiumeng/PycharmProjects/day21
PYCHARM_HOSTED 1
PYTHONPATH /Users/qiumeng/PycharmProjects/day21
SHELL /bin/bash
PYTHONIOENCODING UTF-8
PYENV_DIR /Applications/PyCharm.app/Contents/bin
PYENV_ROOT /Users/qiumeng/.pyenv
GOPATH /Users/qiumeng/GoLang
USER qiumeng
GOROOT /usr/local/Cellar/go/1.8.3/libexec
TMPDIR /var/folders/k5/9fcwbxhn1_d_x3lxvs868m6c0000gn/T/
PYENV_HOOK_PATH /Users/qiumeng/.pyenv/pyenv.d:/usr/local/Cellar/pyenv/1.1.3/pyenv.d:/usr/local/etc/pyenv.d:/etc/pyenv.d:/usr/lib/pyenv/hooks
SSH_AUTH_SOCK /private/tmp/com.apple.launchd.kT7ERQ3lJ4/Listeners
DJANGO_SETTINGS_MODULE day21.settings
XPC_FLAGS 0x0
PYTHONUNBUFFERED 1
__CF_USER_TEXT_ENCODING 0x1F5:0x19:0x34
Apple_PubSub_Socket_Render /private/tmp/com.apple.launchd.nEfmDxko1b/Render
LC_CTYPE zh_CN.UTF-8
HOME /Users/qiumeng
TZ UTC
RUN_MAIN true
SERVER_NAME 1.0.0.127.in-addr.arpa
GATEWAY_INTERFACE CGI/1.1
SERVER_PORT 8000
REMOTE_HOST
CONTENT_LENGTH
SCRIPT_NAME
SERVER_PROTOCOL HTTP/1.1
SERVER_SOFTWARE WSGIServer/0.2
REQUEST_METHOD GET
PATH_INFO /index/
QUERY_STRING
REMOTE_ADDR 127.0.0.1
CONTENT_TYPE text/plain
HTTP_HOST 127.0.0.1:8000
HTTP_CONNECTION keep-alive
HTTP_CACHE_CONTROL max-age=0
HTTP_USER_AGENT Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36
HTTP_UPGRADE_INSECURE_REQUESTS 1
HTTP_ACCEPT text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
HTTP_ACCEPT_ENCODING gzip, deflate, br
HTTP_ACCEPT_LANGUAGE zh-CN,zh;q=0.9
HTTP_COOKIE csrftoken=Ne1RJ3duPUV5mFJysr9r48fgEZCaJY75RFsh6ujbELqQYYzxOynhoLSVT3GnUblx
wsgi.input <_io.BufferedReader name=5>
wsgi.errors <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>
wsgi.version (1, 0)
wsgi.run_once False
wsgi.url_scheme http
wsgi.multithread True
wsgi.multiprocess False
wsgi.file_wrapper <class 'wsgiref.util.FileWrapper'>