add by zhj: Django将所有http header(包括你自定义的http header)都放在了HttpRequest.META这个Python标准字典中,当然HttpRequest.META

中还包含其它一些键值对,这些键值对是Django加进去的,如SERVER_PORT等。对于http header,Django进行了重命名,规则如下

(1) 所有header名大写,将连接符“-”改为下划线“_”

(2) 除CONTENT_TYPE和CONTENT_LENGTH,其它的header名称前加“HTTP_”前缀

参见 https://docs.djangoproject.com/en/1.6/ref/request-response/#django.http.HttpRequest.META

我个人比较喜欢跟踪源代码来查看,源代码如下,

class WSGIRequestHandler(BaseHTTPRequestHandler):

    server_version = "WSGIServer/" + __version__

    def get_environ(self):
env = self.server.base_environ.copy()
env['SERVER_PROTOCOL'] = self.request_version
env['REQUEST_METHOD'] = self.command
if '?' in self.path:
path,query = self.path.split('?',1)
else:
path,query = self.path,'' env['PATH_INFO'] = urllib.unquote(path)
env['QUERY_STRING'] = query host = self.address_string()
if host != self.client_address[0]:
env['REMOTE_HOST'] = host
env['REMOTE_ADDR'] = self.client_address[0] if self.headers.typeheader is None:
env['CONTENT_TYPE'] = self.headers.type
else:
env['CONTENT_TYPE'] = self.headers.typeheader length = self.headers.getheader('content-length')
if length:
env['CONTENT_LENGTH'] = length for h in self.headers.headers:
k,v = h.split(':',1)
k=k.replace('-','_').upper(); v=v.strip()
if k in env:
continue # skip content length, type,etc.
if 'HTTP_'+k in env:
env['HTTP_'+k] += ','+v # comma-separate multiple headers
else:
env['HTTP_'+k] = v
return env def get_stderr(self):
return sys.stderr def handle(self):
"""Handle a single HTTP request""" self.raw_requestline = self.rfile.readline()
if not self.parse_request(): # An error code has been sent, just exit
return handler = ServerHandler(
self.rfile, self.wfile, self.get_stderr(), self.get_environ()
)
handler.request_handler = self # backpointer for logging
handler.run(self.server.get_app())
class WSGIRequest(http.HttpRequest):
def __init__(self, environ):
script_name = base.get_script_name(environ)
path_info = base.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
self.path = '%s/%s' % (script_name.rstrip('/'), path_info.lstrip('/'))
self.META = environ
self.META['PATH_INFO'] = path_info
self.META['SCRIPT_NAME'] = script_name
self.method = environ['REQUEST_METHOD'].upper()
_, content_params = self._parse_content_type(self.META.get('CONTENT_TYPE', ''))
if 'charset' in content_params:
try:
codecs.lookup(content_params['charset'])
except LookupError:
pass
else:
self.encoding = content_params['charset']
self._post_parse_error = False
try:
content_length = int(self.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

WSGIRequest类实例化方法__init__(self,environ)中第二个参数就是WSGIRequestHandler.get_environ()方法返回的数据

WSGIRequest.META在environ的基础上加了一些键值对

原文:http://callmepeanut.blog.51cto.com/7756998/1390769

用Django做后台,客户端向Django请求数据,为了区分不同的请求,想把每个请求类别加在HTTP头部(headers)里面。

先做实验,就用Python的httplib库来做模拟客户端,参考网上写出模拟代码如下:

#coding=utf8
import httplib
httpClient = None
try:
myheaders = { "category": "Books",
"id": "",
'My-Agent': "Super brower"
}
httpClient = httplib.HTTPConnection('10.14.1XX.XXX',8086,timeout=30)
httpClient.request('GET','/headinfo/',headers=myheaders)
response = httpClient.getresponse()
print response.status
print response.reason
print response.read()
except Exception, e:
print e
finally:
if httpClient:
httpClient.close()
 

其中'/headinfo/'为服务器的响应目录。

然后是服务端的响应代码,《The Django Book》第七章有个获取META的例子:

# GOOD (VERSION 2)
def ua_display_good2(request):
ua = request.META.get('HTTP_USER_AGENT', 'unknown')
return HttpResponse("Your browser is %s" % ua)
 

正好看过这个例子,就模拟上面的这个写了一个能够返回客户端自定义头部的模块:

from django.http import HttpResponse
def headinfo(request):
category = request.META.get('CATEGORY', 'unkown')
id = request.META.get('ID','unkown')
agent = request.META.get('MY-AGENT','unkown')
html = "<html><body>Category is %s, id is %s, agent is %s</body></html>" % (category, id, agent)
return HttpResponse(html)
 

运行结果如下:

$python get.py
#输出:
#
#OK
#<html><body>Category is unkown, id is unkown, agent is unkown</body></html>
 

可以看到服务器成功响应了,但是却没有返回自定义的内容。

我以为是客户端模拟headers出问题了,查找和试验了许多次都没有返回正确的结果。后来去查Django的文档,发现了相关的描述:

HttpRequest.META

A standard Python dictionary containing all available HTTP headers. Available headers depend on the client and server, but here are some examples:

  • CONTENT_LENGTH – the length of the request body (as a string).

  • CONTENT_TYPE – the MIME type of the request body.

  • HTTP_ACCEPT_ENCODING – Acceptable encodings for the response.

  • HTTP_ACCEPT_LANGUAGE – Acceptable languages for the response.

  • HTTP_HOST – The HTTP Host header sent by the client.

  • HTTP_REFERER – The referring page, if any.

  • HTTP_USER_AGENT – The client’s user-agent string.

  • QUERY_STRING – The query string, as a single (unparsed) string.

  • REMOTE_ADDR – The IP address of the client.

  • REMOTE_HOST – The hostname of the client.

  • REMOTE_USER – The user authenticated by the Web server, if any.

  • REQUEST_METHOD – A string such as "GET" or "POST".

  • SERVER_NAME – The hostname of the server.

  • SERVER_PORT – The port of the server (as a string).

With the exception of CONTENT_LENGTH and CONTENT_TYPE, as given above, any HTTP headers in the request are converted toMETA keys by converting all characters to uppercase, replacing any hyphens with underscores and adding an HTTP_ prefix to the name. So, for example, a header called X-Bender would be mapped to the META key HTTP_X_BENDER.

其中红色的部分说明是说除了两个特例之外,其他的头部在META字典中的key值都会被加上“HTTP_”的前缀,终于找到问题所在了,赶紧修改服务端代码:

category = request.META.get('HTTP_CATEGORY', 'unkown')
id = request.META.get('HTTP_ID','unkown')
 

果然,执行后返回了想要的结果:

$python get.py
#正确的输出:
#
#OK
#<html><body>Category is Books, id is 21, agent is Super brower</body></html>

得到的经验就是遇到问题要多查文档,搜索引擎并不一定比文档更高效。

Django接收自定义http header(转)的更多相关文章

  1. android 发送自定义广播以及接收自定义广播

    发送自定义广播程序: 布局文件: <?xml version="1.0" encoding="utf-8"?> <LinearLayout x ...

  2. 自定义 Preference Header 布局

    1. Preference Header 概述: 对于什么是 Preference Header,以及何时使用 Preference Header,请参考我的另一篇博文: 何时使用 Preferenc ...

  3. iOS-AFNetworking封装Get(自定义HTTP Header)和Post请求及文件下载

    前面提到AFNetworking是一个很强大的网络三方库,首先你需要引入AFNetworking三方库:如封装的有误还请指出,谢谢! 1.Get请求 /**Get请求 url 服务器请求地址 succ ...

  4. 基于django的自定义简单session功能

    基于django的自定义简单session功能 简单思路: 1.建立自定义session数据库 2.登入时将用户名和密码存入session库 3.将自定义的随机session_id写入cookie中 ...

  5. Django实现自定义template页面并在admin site的app模块中加入自定义跳转链接

    在文章 Django实现自定义template页面并在admin site的app模块中加入自定义跳转链接(一) 中我们成功的为/feedback/feedback_stats/路径自定义了使用tem ...

  6. Django 编写自定义的 404 / 500 报错界面

    Django 编写自定义的 404 / 500 报错界面 1. 首先 setting.py 文件中的 debug 参数设置成 false ,不启用调试. DEBUG = False 2. 在 temp ...

  7. Vuejs中slot实现自定义组件header、footer等

    Vuejs中slot实现自定义组件header.footer等 vue中的slot主要负责内容分发,之前有介绍过slot的内容,具体链接:http://www.cnblogs.com/vipzhou/ ...

  8. django admin自定义

    django admin自定义 class CustomerAdmin(admin.ModelAdmin): list_display = ('id','name','qq','consultant' ...

  9. Nginx获取自定义头部header的值

    http://blog.csdn.net/xbynet/article/details/51899286?_t=t http://shift-alt-ctrl.iteye.com/blog/23314 ...

随机推荐

  1. VMware12激活码,win10激活码

    VMware Workstation 12序列号: 5A02H-AU243-TZJ49-GTC7K-3C61N win10激活码:这里在网上搜集到很多激活码,可能有的不能用.   WRUF7-AFI0 ...

  2. linphone 在am335x的编译过程

    环境变量: export PREFIX=/usr export HOSTTPL=arm-linux-gnueabihf export INSTALLDIR=/home/elinux/linphone/ ...

  3. java 错误汇总

    一.怎么处理警告:编码 GBK 的不可映射字符 解决办法是:应该使用-encoding参数指明编码方式:javac -encoding UTF-8 XX.java,这下没警告了,运行也正确了在JCre ...

  4. notification 报错the method build() is undefined for the type Notificatin.Builder

    notification 报错the method build() is undefined for the type Notificatin.Builder 这事api版本号太低导致的 Notifi ...

  5. phpstorm 中文版 支持BUG调试 IDE

    下载地址:http://dx2.7down.net/soft/P/phpstorm8_cn.zip

  6. EasyUI 创建对话框

    对话框是特殊的窗口,它能包括上面的工具栏和下面的按钮.默认对话框不能改变大小,但是用户可以设置resizeable属性为true来使它可以被改变大小:对话框非常简单,可以使用DIV标记创建: < ...

  7. MapReduce总体架构分析

    转自:http://blog.csdn.net/Androidlushangderen/article/details/41051027 继前段时间分析Redis源码一段时间之后,我即将开始接下来的一 ...

  8. 解决cookie跨域访问.2

    v一.前言 随着项目模块越来越多,很多模块现在都是独立部署.模块之间的交流有时可能会通过cookie来完成.比如说门户和应用,分别部署在不同的机器或者web容器中,假如用户登陆之后会在浏览器客户端写入 ...

  9. C++标准库之mutex

    互斥锁有可重入.不可重入之分.C++标准库中用mutex表示不可重入的互斥锁,用recursive_mutex表示可重入的互斥锁.为这两个类增加根据时间来阻塞线程的能力,就又有了两个新的互斥锁:tim ...

  10. 深入理解Mybatis中sqlSessionFactory机制原理

    对于任何框架而言,在使用前都要进行一系列的初始化,MyBatis也不例外.本章将通过以下几点详细介绍MyBatis的初始化过程. 1.MyBatis的初始化做了什么 2. MyBatis基于XML配置 ...