在AppEngine上对上传的二进制数据进行Base64编码
我一直在尝试将用户(在这个情况下是一个可信的管理员)的图像数据进行Base64编码,这样可以尽量减少对BlobStore的调用。每次我尝试编码时,都会收到一个错误提示:
Error uploading image: 'ascii' codec can't decode byte 0x89 in position 0: ordinal not in range(128)
我在网上搜索了这个错误(不太重要的部分),发现可能和Unicode有关(?)。模板部分只是一个基本的上传表单,而处理程序包含以下代码:
def post(self,id):
logging.info("ImagestoreHandler#post %s", self.request.path)
fileupload = self.request.POST.get("file",None)
if fileupload is None : return self.error(400)
content_type = fileupload.type or getContentType( fileupload.filename )
if content_type is None:
self.error(400)
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write( "Unsupported image type: " + fileupload.filename )
return
logging.debug( "File upload: %s, mime type: %s", fileupload.filename, content_type )
try:
(img_name, img_url) = self._store_image(
fileupload.filename, fileupload.file, content_type )
self.response.headers['Location'] = img_url
ex=None
except Exception, err:
logging.exception( "Error while storing image" )
self.error(400)
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write("Error uploading image: " + str(err))
return
#self.redirect(urlBase % img.key() ) #dummy redirect is acceptable for non-AJAX clients,
# location header should be acceptable for true REST clients, however AJAX requests
# might not be able to access the location header so we'll write a 200 response with
# the new URL in the response body:
acceptType = self.request.accept.best_match( listRenderers.keys() )
out = self.response.out
if acceptType == 'application/json':
self.response.headers['Content-Type'] = 'application/json'
out.write( '{"name":"%s","href":"%s"}' % ( img_name, img_url ) )
elif re.search( 'html|xml', acceptType ):
self.response.headers['Content-Type'] = 'text/html'
out.write( '<a href="%s">%s</a>' % ( img_url, img_name) )
def _store_image(self, name, file, content_type):
"""POST handler delegates to this method for actual image storage; as
a result, alternate implementation may easily override the storage
mechanism without rewriting the same content-type handling.
This method returns a tuple of file name and image URL."""
img_enc = base64.b64encode(file.read())
img_enc_struct = "data:%s;base64,%s" % (content_type, img_enc)
img = Image( name=name, data=img_enc_struct )
img.put()
logging.info("Saved image to key %s", img.key() )
return ( str(img.name), img.key() )
我的图像模型:
from google.appengine.ext import db
class Image(db.Model):
name = db.StringProperty(required=True)
data = db.TextProperty(required=True)
created = db.DateTimeProperty(auto_now_add=True)
owner = db.UserProperty(auto_current_user_add=True)
非常感谢任何帮助。这段代码,除了我在_store_image中的图像编码,来自gvdent的blooger分支,链接在这里。
1 个回答
4
你的商店图片代码可能是这样的……
img = Image( name=name, data=file.read() )
img.put()
return ( str(img.name), img.key() )
把二进制数据做成base64编码可能会让数据变得更大,同时也会增加处理这些数据时的时间。
而Blobstore使用的存储结构和数据存储是一样的,所以它只是让文件上传和下载变得更简单。