最近同事负责的项目后台访问的时候会出现部分cookie被吞掉并截断的情况,情况举例如下:

假如前台传过来的cookie为:

id=100; name=测试; token=957439858943845;

这时传到django后台后获取到的cookie就会从name开始截断,只剩下id=100这一个cookie信息。

通过后台抓包和ngnix日志输出定位到问题出在了django这一层,我负责的项目却没有这个问题,于是查看了二者的版本,他环境上的django版本是1.5.12,而我的django版本是1.8.17,难道真的是django版本的问题?于是就换了个环境分别测试了两个版本的访问情况,果然把1.5.12升级为1.8.17后就可以正常使用cookie了。

解决问题不能仅仅是解决,而是要搞清楚问题的原因在哪,于是我研究了一下django的两个版本源码对比,发现django1.5.12版本在处理cookie上使用了Cookie.SimpleCookie,源码对应的文件为django/django/http/cookie.py。

from __future__ import absolute_import, unicode_literalsfrom django.utils.encoding import force_str
from django.utils import six
from django.utils.six.moves import http_cookies# Some versions of Python 2.7 and later won't need this encoding bug fix:
_cookie_encodes_correctly = http_cookies.SimpleCookie().value_encode(';') == (';', '"\\073"')
# See ticket #13007, http://bugs.python.org/issue2193 and http://trac.edgewall.org/ticket/2256
_tc = http_cookies.SimpleCookie()
try:_tc.load(str('foo:bar=1'))_cookie_allows_colon_in_names = True
except http_cookies.CookieError:_cookie_allows_colon_in_names = Falseif _cookie_encodes_correctly and _cookie_allows_colon_in_names:SimpleCookie = http_cookies.SimpleCookie
else:Morsel = http_cookies.Morselclass SimpleCookie(http_cookies.SimpleCookie):if not _cookie_encodes_correctly:def value_encode(self, val):# Some browsers do not support quoted-string from RFC 2109,# including some versions of Safari and Internet Explorer.# These browsers split on ';', and some versions of Safari# are known to split on ', '. Therefore, we encode ';' and ','# SimpleCookie already does the hard work of encoding and decoding.# It uses octal sequences like '\\012' for newline etc.# and non-ASCII chars. We just make use of this mechanism, to# avoid introducing two encoding schemes which would be confusing# and especially awkward for javascript.# NB, contrary to Python docs, value_encode returns a tuple containing# (real val, encoded_val)val, encoded = super(SimpleCookie, self).value_encode(val)encoded = encoded.replace(";", "\\073").replace(",","\\054")# If encoded now contains any quoted chars, we need double quotes# around the whole string.if "\\" in encoded and not encoded.startswith('"'):encoded = '"' + encoded + '"'return val, encodedif not _cookie_allows_colon_in_names:def load(self, rawdata):self.bad_cookies = set()if not six.PY3 and isinstance(rawdata, six.text_type):rawdata = force_str(rawdata)super(SimpleCookie, self).load(rawdata)for key in self.bad_cookies:del self[key]# override private __set() method:# (needed for using our Morsel, and for laxness with CookieErrordef _BaseCookie__set(self, key, real_value, coded_value):key = force_str(key)try:M = self.get(key, Morsel())M.set(key, real_value, coded_value)dict.__setitem__(self, key, M)except http_cookies.CookieError:self.bad_cookies.add(key)dict.__setitem__(self, key, http_cookies.Morsel())def parse_cookie(cookie):if cookie == '':return {}if not isinstance(cookie, http_cookies.BaseCookie):try:c = SimpleCookie()c.load(cookie)except http_cookies.CookieError:# Invalid cookiereturn {}else:c = cookiecookiedict = {}for key in c.keys():cookiedict[key] = c.get(key).valuereturn cookiedict

关于Cookie.SimpleCookie,Cooke模块中定义了4个直接操作Cookie的类:BaseCookie、SimpleCookie、SerialCookie、 SmartCookie。其中,BaseCookie是基类,定义了操作Cookie的公共部分,其他3个类都继承自BaseCookie,它们之间的区 别仅仅在于序列化数据的方式不同。

BaseCookie基类: BaseCookies的行为非常像dict,可以用键/值对的形式来操作它,但是kye必须是字符串,value是Morsel对象 。BaseCookies定义了编码/解码,输入/输出操作的公共规范。

Morsel类 : 用于表示Cookie中每一项数据的属性而抽象的类。这些属性包括:expires, path, comment, domain, max-age, secure, version等等

综上所述,因为中间层nginx会把中文转换为16进制数据,到达SimpleCookie这边不支持了这种编码,因此就将后面的cookie信息全部截断丢弃。

而1.8.17版本的django对cookie的处理中,并没有使用SimpleCookie进行处理,只是简单的对格式等进行了转换,源码如下:

from __future__ import unicode_literalsimport sysfrom django.utils import six
from django.utils.encoding import force_str
from django.utils.six.moves import http_cookies# Some versions of Python 2.7 and later won't need this encoding bug fix:
_cookie_encodes_correctly = http_cookies.SimpleCookie().value_encode(';') == (';', '"\\073"')
# See ticket #13007, http://bugs.python.org/issue2193 and http://trac.edgewall.org/ticket/2256
_tc = http_cookies.SimpleCookie()
try:_tc.load(str('foo:bar=1'))_cookie_allows_colon_in_names = True
except http_cookies.CookieError:_cookie_allows_colon_in_names = False# Cookie pickling bug is fixed in Python 2.7.9 and Python 3.4.3+
# http://bugs.python.org/issue22775
cookie_pickles_properly = ((sys.version_info[:2] == (2, 7) and sys.version_info >= (2, 7, 9)) orsys.version_info >= (3, 4, 3)
)if _cookie_encodes_correctly and _cookie_allows_colon_in_names and cookie_pickles_properly:SimpleCookie = http_cookies.SimpleCookie
else:Morsel = http_cookies.Morselclass SimpleCookie(http_cookies.SimpleCookie):if not cookie_pickles_properly:def __setitem__(self, key, value):# Apply the fix from http://bugs.python.org/issue22775 where# it's not fixed in Python itselfif isinstance(value, Morsel):# allow assignment of constructed Morsels (e.g. for pickling)dict.__setitem__(self, key, value)else:super(SimpleCookie, self).__setitem__(key, value)if not _cookie_encodes_correctly:def value_encode(self, val):# Some browsers do not support quoted-string from RFC 2109,# including some versions of Safari and Internet Explorer.# These browsers split on ';', and some versions of Safari# are known to split on ', '. Therefore, we encode ';' and ','# SimpleCookie already does the hard work of encoding and decoding.# It uses octal sequences like '\\012' for newline etc.# and non-ASCII chars. We just make use of this mechanism, to# avoid introducing two encoding schemes which would be confusing# and especially awkward for javascript.# NB, contrary to Python docs, value_encode returns a tuple containing# (real val, encoded_val)val, encoded = super(SimpleCookie, self).value_encode(val)encoded = encoded.replace(";", "\\073").replace(",", "\\054")# If encoded now contains any quoted chars, we need double quotes# around the whole string.if "\\" in encoded and not encoded.startswith('"'):encoded = '"' + encoded + '"'return val, encodedif not _cookie_allows_colon_in_names:def load(self, rawdata):self.bad_cookies = set()if six.PY2 and isinstance(rawdata, six.text_type):rawdata = force_str(rawdata)super(SimpleCookie, self).load(rawdata)for key in self.bad_cookies:del self[key]# override private __set() method:# (needed for using our Morsel, and for laxness with CookieErrordef _BaseCookie__set(self, key, real_value, coded_value):key = force_str(key)try:M = self.get(key, Morsel())M.set(key, real_value, coded_value)dict.__setitem__(self, key, M)except http_cookies.CookieError:if not hasattr(self, 'bad_cookies'):self.bad_cookies = set()self.bad_cookies.add(key)dict.__setitem__(self, key, http_cookies.Morsel())def parse_cookie(cookie):"""Return a dictionary parsed from a `Cookie:` header string."""cookiedict = {}if six.PY2:cookie = force_str(cookie)for chunk in cookie.split(str(';')):if str('=') in chunk:key, val = chunk.split(str('='), 1)else:# Assume an empty name per# https://bugzilla.mozilla.org/show_bug.cgi?id=169091key, val = str(''), chunkkey, val = key.strip(), val.strip()if key or val:# unquote using Python's algorithm.cookiedict[key] = http_cookies._unquote(val)return cookiedict

而看了最新的django版本源码,发现直接把上面的一部分处理删除掉了。

from http import cookies# For backwards compatibility in Django 2.1.
SimpleCookie = cookies.SimpleCookiedef parse_cookie(cookie):"""Return a dictionary parsed from a `Cookie:` header string."""cookiedict = {}for chunk in cookie.split(';'):if '=' in chunk:key, val = chunk.split('=', 1)else:# Assume an empty name per# https://bugzilla.mozilla.org/show_bug.cgi?id=169091key, val = '', chunkkey, val = key.strip(), val.strip()if key or val:# unquote using Python's algorithm.cookiedict[key] = cookies._unquote(val)return cookiedict

至此,升级下django就可以解决这个问题啦。(*^__^*) 嘻嘻

Django源码cookie解读:关于中文cookie会被吞掉并截断的问题。相关推荐

  1. Django源码分析5:session会话中间件分析

    django源码分析 本文环境python3.5.2,django1.10.x系列 1.这次分析django框架中的会话中间件. 2.会话保持是目前框架都支持的一个功能,因为http是无状态协议,无法 ...

  2. Django源码分析3:处理请求wsgi分析与视图View

    django源码分析 本文环境python3.5.2,django1.10.x系列 根据前上一篇runserver的博文,已经分析了本地调试服务器的大致流程,现在我们来分析一下当runserver运行 ...

  3. Django源码分析10:makemigrations命令概述

    django源码分析 本文环境python3.5.2,django1.10.x系列 django源码分析-makemigrations命令概述 Django项目中的数据库管理命令就是通过makemig ...

  4. Django源码分析9:model.py表结构的初始化概述

    django源码分析 本文环境python3.5.2,django1.10.x系列 django源码分析-model概述 Django项目中提供了内置的orm框架,只需要在models.py文件中添加 ...

  5. Django源码分析8:单元测试test命令浅析

    django源码分析 本文环境python3.5.2,django1.10.x系列 django源码分析-test命令分析 Django项目中提供了,test命令行命令来执行django的单元测试,该 ...

  6. Django源码分析7:migrate命令的浅析

    django源码分析 本文环境python3.5.2,django1.10.x系列 django源码分析-migrate命令分析 Django项目中提供了,通过migrations操作数据库的结构的命 ...

  7. Django源码分析6:auth认证及登陆保持

    django源码分析 本文环境python3.5.2,django1.10.x系列 1.这次分析django框架中登陆认证与接口权限检查. 2.在后端开发中,难免会对接口进行权限验证,其中对于接口是否 ...

  8. Django源码分析4:staticfiles静态文件处理中间件分析

    django源码分析 本文环境python3.5.2,django1.10.x系列1.在上一篇文章中已经分析过handler的处理过程,其中load_middleware就是将配置的中间件进行初始化, ...

  9. Django源码分析2:本地运行runserver分析

    django源码分析 本文环境python3.5.2,django1.10.x系列1.根据上一篇文章分析了,django-admin startproject与startapp的分析流程后,根据dja ...

最新文章

  1. Perl 教学 子程序
  2. java MDC_log4j MDC实现日志追踪
  3. java的本地文件操作
  4. 牛津临床和实验室调查手册 Oxford Handbook of Clinical and Laboratory Investigation
  5. LeetCode Algorithm 1052. 爱生气的书店老板
  6. eclipse export jar file 和 runnable jar file 的区别
  7. 错误: 找不到或无法加载主类 org.apache.hadoop.hbase.util.GetJavaProperty
  8. 计算机网络之网络概述:3、性能指标(速率、带宽、吞吐量、时延、RTT、利用率)
  9. PHP排雷之编码问题
  10. UCHome风格模版 框架核心代码提取
  11. JSON.stringify的三个参数(转载)
  12. 利用ant脚本 自动构建svn增量/全量 系统程序升级包
  13. 大学生计算机应用论文,大学生计算机应用论文(共1178字).doc
  14. Duilib使用---颜色配置
  15. python matplotlib绘图总结
  16. [摘录]谁说大象不能跳舞目录
  17. 如何制作趣味头像?分享几种制作头像的方法
  18. PCM音频格式的深入理解
  19. jQuery笔试题汇总整理--2018
  20. 手把手使用Android自带SQLite数据库(1)—— 建立核心文件

热门文章

  1. 奇数位升序偶数位降序的链表进行排序
  2. JSP打印九九乘法表和表格
  3. python练习题(3)--字符串及正则表达式的应用
  4. 首席新媒体黎想告诉你,不花钱做互联网推广!这些方式了解一下
  5. JAVA:Java Swing 练习题
  6. 利用python构建马科维茨_利用马科维茨投资组合模型建立Alpha策略
  7. Spark入门学习交流—Spark生态圈
  8. 英语介绍计算机,计算机英语自我介绍
  9. 2022谷粒商城学习笔记(二十三)分布式事务
  10. 阿里云服务器受攻击总结