google app engine + python:上传到blobstore会导致错误的编码

时间:2014-05-30 13:58:28

标签: python google-app-engine blobstore

我尝试使用以下HTML表单将blob上传到Google App Engine的blobstore:

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
</head>
<body>
<form id=upload action={{upload_url}} method=post enctype=multipart/form-data>
  Name: <input type=text name=name>
  Your photo: <input type=file name=image required=required><br><br>
  <input type=submit value=submit>
</form>
</body>
</html>

模板变量{{upload_url}}的值由服务器端的upload_url = blobstore.create_upload_url('/upload')获取。后处理脚本如下:

    class Test(ndb.Model):
        name = StringProperty()
        image = StringProperty()

    test = Test()
    test.name = self.request.get('name')
    image = self.get_uploads('image')[0]
    test.image = str(image.key())
    test.put()

通常,name字段将填充非英文字符(例如,中文)。以上程序在我的本地SDK上运行正常。但是,当程序在Google App Engine上运行时,name编码错误。那么问题是什么?

2 个答案:

答案 0 :(得分:1)

您不必在元标记参数前加注引号:<meta charset="UTF-8">?另外,请尝试:<meta http-equiv="content-type" content="text/html; charset=utf-8" />。并且,请确保以UTF-8编码保存模板的文本文档。

答案 1 :(得分:1)

多年来刚刚发现这是一个老bug,请参阅here。有两种解决方案:

(1)将以下语句添加到app.yaml:

libraries:
- name: webob
  version: "1.2.3"

(2)使用以下内容添加文件appengine_config.yaml:

# -*- coding: utf-8 -*-
from webob import multidict

def from_fieldstorage(cls, fs):
    """Create a dict from a cgi.FieldStorage instance.
    See this for more details:
    http://code.google.com/p/googleappengine/issues/detail?id=2749
    """
    import base64
    import quopri

    obj = cls()
    if fs.list:
        # fs.list can be None when there's nothing to parse
        for field in fs.list:
            if field.filename:
                obj.add(field.name, field)
            else:
                # first, set a common charset to utf-8.
                common_charset = 'utf-8'
                # second, check Content-Transfer-Encoding and decode
                # the value appropriately
                field_value = field.value
                transfer_encoding = field.headers.get('Content-Transfer-Encoding', None)
                if transfer_encoding == 'base64':
                    field_value = base64.b64decode(field_value)
                if transfer_encoding == 'quoted-printable':
                    field_value = quopri.decodestring(field_value)
                if field.type_options.has_key('charset') and field.type_options['charset'] != common_charset:
                    # decode with a charset specified in each
                    # multipart, and then encode it again with a
                    # charset specified in top level FieldStorage
                    field_value = field_value.decode(field.type_options['charset']).encode(common_charset)
                    # TODO: Should we take care of field.name here?
                    obj.add(field.name, field_value)
    return obj

multidict.MultiDict.from_fieldstorage = classmethod(from_fieldstorage)