使用Django REST Framework在GCP上传图片时遭遇UnicodeDecodeError错误求助
问题排查与解决方法
这个UnicodeDecodeError的核心原因是你错误地处理了上传的文件对象,把二进制图片当成UTF-8文本内容来解析,同时误用了GCS的上传方法。下面一步步给你拆解问题和解决思路:
问题根源分析
- 错误的文件对象处理:
str(up_file)会把Django接收到的InMemoryUploadedFile对象转成类似<InMemoryUploadedFile: test.jpg (image/jpeg)>的字符串,这不是你本地的文件路径,直接拼接到upload_from_filename里会导致GCS尝试读取一个不存在的文件,或者错误地解析二进制内容为文本。 - 二进制文件的编码冲突:图片是二进制格式(比如JPG开头是
0xff),当代码尝试用UTF-8解码这些二进制字节时,就会触发UnicodeDecodeError。
推荐解决方案:直接从文件对象上传(高效且避免本地存储)
修改你的上传函数,直接使用Django提供的文件对象上传到GCS,不需要保存到本地:
def post(self, request): up_file = request.data['file'] print('******', request.data) # 初始化GCS客户端和Bucket client = storage.Client() bucket = client.bucket(settings.GOOGLE_CLOUD_STORAGE_BUCKET) # 用上传文件的原始文件名作为GCS中的Blob名称 blob = bucket.blob(up_file.name) # 应用settings中配置的缓存控制规则 blob.cache_control = settings.GOOGLE_CLOUD_STORAGE_DEFAULT_CACHE_CONTROL # 将文件指针移到开头(确保读取完整内容) up_file.seek(0) # 直接从文件对象上传,同时指定文件类型 blob.upload_from_file(up_file, content_type=up_file.content_type) # 返回GCS中文件的公开访问URL(或者根据需求返回文件名) return Response(blob.public_url, status.HTTP_201_CREATED)
关键改进点:
- 使用
up_file.name获取上传文件的原始文件名,避免乱码和无效路径 upload_from_file直接读取请求中的文件流,无需本地存储,提升效率- 设置
content_type让GCS正确识别文件类型,确保前端能正常访问图片 seek(0)确保文件指针回到起始位置,因为Django在解析请求时可能已经读取过文件内容
备选方案:先保存到本地再上传(不推荐)
如果你的业务逻辑必须先将文件保存到本地,需要用二进制模式写入文件,避免编码错误:
def post(self, request): up_file = request.data['file'] print('******', request.data) # 定义本地保存路径,使用原始文件名 local_file_path = f'C:/Users/tiwar/Downloads/{up_file.name}' # 用二进制模式写入文件,避免编码问题 with open(local_file_path, 'wb') as f: for chunk in up_file.chunks(): f.write(chunk) # 上传到GCS client = storage.Client() bucket = client.bucket(settings.GOOGLE_CLOUD_STORAGE_BUCKET) blob = bucket.blob(up_file.name) blob.cache_control = settings.GOOGLE_CLOUD_STORAGE_DEFAULT_CACHE_CONTROL blob.upload_from_filename(local_file_path, content_type=up_file.content_type) return Response(up_file.name, status.HTTP_201_CREATED)
额外注意事项
- Postman配置:确保请求用
form-data格式,键名为file,类型选择File,然后选择要上传的图片文件 - GCS权限:确认你的服务账号拥有
Storage Object Creator或更高权限,否则会出现上传权限错误 - settings配置:你的
DEFAULT_FILE_STORAGE配置是正确的,但如果用自定义上传函数,这个配置不会直接生效,需要手动设置cache_control等参数
内容的提问来源于stack exchange,提问作者Code_Breaker
相关产品推荐
相关产品推荐

