很久以前, Cookies就已成为HTTP协议的一部分. 现有的web开发框架提供了简单的访问cookies的接口. 因此, 程序员几乎不用担心怎样去格式化cookies数据或者确保头的正确发送. 明白cookies是怎样工作以及有哪些工作模式是很让人受启发的事情.
Cookie模块实现了对cookies的解析, 其大多是兼容RFC 2109的. 它没有严重按照标准是因为MSIE 3.0x不支持整个标准.
Cookies可以用作状态管理, 通常被服务器存储并由客户端返回. 最普通的创建cookies的用法可以如下的样子:
import Cookie
c = Cookie.SimpleCookie()
c['mycookie'] = 'cookie_value'
print c
输出是一个有效的Set-Cookie头, 之后会作为HTTP响应传递给客户端.
$ python Cookie_setheaders.py
Set-Cookie: mycookie=cookie_value
控制cookie的其他方面也是有必要的, 比如说期限、路径、域. 事实上, RFC对应的所有的cookies属性可以通过代表cookie值的Morsel对象来操作.
import Cookie
import datetime
def show_cookie(c):
print c
for key, morsel in c.iteritems():
print
print 'key =', morsel.key
print ' value =', morsel.value
print ' coded_value =', morsel.coded_value
for name in morsel.keys():
if morsel[name]:
print ' %s = %s' % (name, morsel[name])
c = Cookie.SimpleCookie()
# A cookie with a value that has to be encoded to fit into the header
c['encoded_value_cookie'] = '"cookie_value"'
c['encoded_value_cookie']['comment'] = 'Notice that this cookie value has escaped quotes'
# A cookie that only applies to part of a site
c['restricted_cookie'] = 'cookie_value'
c['restricted_cookie']['path'] = '/sub/path'
c['restricted_cookie']['domain'] = 'PyMOTW'
c['restricted_cookie']['secure'] = True
# A cookie that expires in 5 minutes
c['with_max_age'] = 'expires in 5 minutes'
c['with_max_age']['max-age'] = 300 # seconds
# A cookie that expires at a specific time
c['expires_at_time'] = 'cookie_value'
expires = datetime.datetime.now() + datetime.timedelta(hours=1)
c['expires_at_time']['expires'] = expires.strftime('%a, %d %b %Y %H:%M:%S')
show_cookie(c)
以上的例子包括了两个不同的设置cookies期限的方法. 你可以设置max-age为一些秒数, 或者指定一个cookie失效的时间和日期.
$ python Cookie_Morsel.py
Set-Cookie: encoded_value_cookie="\"cookie_value\""; Comment=Notice that this cookie value has escaped quotes
Set-Cookie: expires_at_time=cookie_value; expires=Sun, 01 Jun 2008 11:37:00
Set-Cookie: restricted_cookie=cookie_value; Domain=PyMOTW; Path=/sub/path; secure
Set-Cookie: with_max_age="expires in 5 minutes"; Max-Age=300
key = restricted_cookie
value = cookie_value
coded_value = cookie_value
domain = PyMOTW
secure = True
path = /sub/path
key = with_max_age
value = expires in 5 minutes
coded_value = "expires in 5 minutes"
max-age = 300
key = encoded_value_cookie
value = "cookie_value"
coded_value = "\"cookie_value\""
comment = Notice that this cookie value has escaped quotes
key = expires_at_time
value = cookie_value
coded_value = cookie_value
expires = Sun, 01 Jun 2008 11:37:00
Cookie和Morsel对象都像是一个字典. Morsel对应以下固定的键值:
一个Cookie对象的键是一些独立的会被cookie存储的名字. 来自于Morsel的键属性的信息也是可用的.
cookie头可能会需要编码后的值以便它们被正确的解析.
import Cookie
c = Cookie.SimpleCookie()
c['integer'] = 5
c['string_with_quotes'] = 'He said, "Hello, World!"'
for name in ['integer', 'string_with_quotes']:
print c[name].key
print ' %s' % c[name]
print ' value=%s' % c[name].value, type(c[name].value)
print ' coded_value=%s' % c[name].coded_value
print
Morsel.value常常是cookie中已经被解码的值, 而 Morsel.coded_value 的值是以一种符合传递给客户端要求的形式来表示的.
$ python Cookie_coded_value.py
integer
Set-Cookie: integer=5
value=5 <type 'str'>
coded_value=5
string_with_quotes
Set-Cookie: string_with_quotes="He said, \"Hello, World!\""
value=He said, "Hello, World!" <type 'str'>
coded_value="He said, \"Hello, World!\""
一旦客户端收到Set-Cookie头, 它会将这些cookies在接下来的请求中作为新的Cookie头返回给服务器. 那么传入的头看起来是:
Cookie: integer=5; string_with_quotes="He said, \"Hello, World!\""
cookies既可以直接从HTTP响应头, 或环境变量HTTP_COOKIE, 这依赖于你的web服务器/框架. 实例化时, 将经过解码的没有头前缀的字符串传递给SimpleCookie, 或者使用 load() .
import Cookie
HTTP_COOKIE = r'integer=5; string_with_quotes="He said, \"Hello, World!\""'
print 'From constructor:'
c = Cookie.SimpleCookie(HTTP_COOKIE)
print c
print
print 'From load():'
c = Cookie.SimpleCookie()
c.load(HTTP_COOKIE)
print c
$ python Cookie_parse.py
From constructor:
Set-Cookie: integer=5
Set-Cookie: string_with_quotes="He said, \"Hello, World!\""
From load():
Set-Cookie: integer=5
Set-Cookie: string_with_quotes="He said, \"Hello, World!\""
除了使用Set-Cookie头外, 使用JavaScript给客户端增加cookies也是可以的. SimpleCookie和Morsel提供一种JavaScript输出格式, 通过使用 js_output() 方法:
import Cookie
c = Cookie.SimpleCookie()
c['mycookie'] = 'cookie_value'
c['another_cookie'] = 'second value'
print c.js_output()
$ python Cookie_js_output.py
<script type="text/javascript">
<!-- begin hiding
document.cookie = "another_cookie="second value"";
// end hiding -->
</script>
<script type="text/javascript">
<!-- begin hiding
document.cookie = "mycookie=cookie_value";
// end hiding -->
</script>
上面所有的例子中都是使用的SimpleCookie类. Cookie模块也提供2个其他的类, SerialCookie和SmartCookie. SerialCookie可以处理任何可以被pickle的值. SmartCookie指明了一个值是否需要被unpickle或者是否是一个简单的值. 由于他们两者都使用了pickle, 他们是你应用中的潜在安全漏洞, 所以你最好不要使用他们. 在服务器上存贮cookie状态, 然后传递给客户端一个会话key, 这是更安全的.