bottle框架使用一个小坑-获取中文参数乱码

Published on with 0 views and 0 comments

背景描述:

在bottle中,获取参数一般使用request.query.items()和request.POST.allitems()获取参数。当参数中有中文的时候,使用python3运行会出现乱码。

解决办法:

from bottle import request
params = dict(request.headers)
args = request.query.decode("utf-8")
for i in args:
params[i] = args[i]
后者针对获取指定的参数使用request.query.getunicode

from bottle import request

params.update(request.query.items())
if 'vaule' in params:
params['Description'] = request.query.getunicode('vaule')
以下内容来自互联网:附参考文献

解释:

   request.query 或 request.forms 都是一个 FormDict 类型,其特点是:当以属性方式访问数据时——如 request.query.foo,返回的结果是 unicode ,当以字典试访问数据时——如 request.query['foo'],则返回的结果是原编码字符串。混合使用的时候,一不小心就会出问题……

    比如:大部分时候都用属性方式,但是某个数据需要有特定默认值的时候,就会习惯性地用字典方式操作: request.query.get("foo", "bar") ,这时就容易出编码错误。这种情况应该使用 request.query.getunicode() 函数。更彻底的方式是用 args=request.query.decode("utf-8") 然后 args.foo 或 args["foo"] 就都可以返回 unicode 了。至于在实际应用中,具体要用哪种方式来处理,就自己看情况选择了。

Note

在Python 2 中所有的键值对都是 byte-strings.如果您需要 unicode, 可以调用FormsDict.getunicode() 或者通过属性访问获取值。这两个方法都会解码字符串(default: utf8),并在失败的时候返回空字符串,而不需要捕获异常UnicodeError:

request.query['city']
'G\xc3\xb6ttingen' # A utf8 byte string
request.query.city
u'Göttingen' # The same string as unicode
在Python 3 中所有的字符串都是 unicode, 但是HTTP 是 byte-based wire 协议的. 服务器需要先解码 byte 字符串,然后将它们传给应用。 安全起见, WSGI 建议使用ISO-8859-1 (aka latin1), 一个可逆的单字节编码,可以后续用其他编码方式重新编码。Bottle 的 FormsDict.getunicode() 和属性访问方法使用这种方式,但是字典访问方法却不使用这种方式,字典访问返回的是服务端实现的未改变的值,它可能不是你想要得到的。

request.query['city']
'Göttingen' # An utf8 string provisionally decoded as ISO-8859-1 by the server
request.query.city
'Göttingen' # The same string correctly re-encoded as utf8 by bottle
如果您需要正确解码值后的整个字典 (e.g. for WTForms),您可以调用 FormsDict.decode() 来得到一个重解码后的副本。

相关知识点:

Unicode and UTF-8
首先我们要理清两个事实:

所有东西(file, network)在计算机中都是以 byte 存储的。但是 byte 本身没有含义,为了使 byte 表示文本,我们需要一套相应的编码方案(比如 ASCII)。
但是事实是世界上的文字很多,而 ASCII 只能表示西方字符,要表示其他字符(比如中文)就无力了。因此每个国家都有一套自己的编码方案来编码自己国家的字符。但这样就产生了混乱(一个byte在不同的编码方案下产生的字符不同)。
为了解决这个问题,产生了 Unicode,每种字符只有一个相应的 coding point 表示。而将 Unicode 字符的 coding point map 到 bytes 的就是 UTF-8, UFT-16。
因此可以这么认为 **Unicode 是一套字符集,而 UFT-8 等是编码方案 **
Unicode in Python3
在 Python3 中,有 str, bytes, bytearray。str type 存储的是 Unicode 字符的coding point,而 bytes type 存储的是 bytes。而且在 Python3 中不会有 bytes 和 str 的隐形转换。(在 Python2 中有,这也往往是bug的来源)

image.png

data type for text or bytes.jpg

image.png

encode vs decode.jpg

image.png

text vs bytes.jpg

"Hello" + b"World"
Traceback (most recent call last):
File "", line 1, in
TypeError: Can't convert 'bytes' object to str implicitly
"Hello" == b"Hello"
False
d = {"Hello": "World"}
d[b"Hello"]
Traceback (most recent call last):
File "", line 1, in
KeyError: b'Hello'
而且在 Python3 中,读取文件时,如果采用文本方式读取(即不是 b mode),Python3 会默认为你用系统编码方案解码(Python2 中不会,读入的是 bytes),但是你可以用 encoding参数制定编码方法

import sys
sys.getfilesystemencoding()
'mbcs'
open('hello.txt').read() # hello.txt 采用 utf8 编码
'浣犲ソ'
open('hello.txt', encoding="utf8").read()
'你好'

参考文献:

  1. https://www.clips.uantwerpen.be/tutorials/python-unicode

  2. https://www.cnblogs.com/space007/p/4838434.html

  3. https://www.jianshu.com/p/2bb8a1300bfd

  4. https://blog.csdn.net/nawenqiang/article/details/79381807

说你懂得生之微末,我便做了这壮大与你看,你说再热闹也终需离散,我便做了这一辈子与你看,你说冷暖自知,我便做了这冬花夏雪与你看,你说恋恋旧日好时光,我便做了这描金绣凤的浮世绘与你看。你说应愁高处不胜寒,我便拱手河山,讨你欢。