Django从S3获取图片触发UTF-8解码错误UnicodeDecodeError如何解决
问题原因
- 报错的核心是二进制图片资源无法用UTF-8编码解码:
obj['Body'].read()返回的是图片的原始二进制字节流,JPEG、PNG等图片格式的文件头本身就不属于UTF-8的合法字符范围,强转文本必然触发UnicodeDecodeError错误。 - DRF的
Response默认会按照JSON格式处理返回内容,本身就不适合用来返回二进制类的媒体资源。
正确实现
你找到的直接返回二进制流的方案是对的,核心逻辑就是不用对字节流做编码转换,直接用HttpResponse返回二进制内容,同时指定正确的content_type即可。
如果不想写死image/jpeg适配多种图片格式,可以直接读取S3返回的文件类型:
@api_view(['GET']) def get_image(request, image): """Get image link""" key = "media/" + str(image) s3 = boto3.client('s3', config=Config(signature_version='s3v4', region_name=settings.AWS_S3_REGION_NAME)) obj = s3.get_object(Bucket=settings.AWS_STORAGE_BUCKET_NAME, Key=key) image_data = obj['Body'].read() return HttpResponse(image_data, content_type=obj['ContentType'])
可选优化方案
如果站点访问量较高,让所有图片流量都经过Django服务转发会消耗大量服务器资源,你可以选择直接返回S3的预签名访问链接,把下载压力直接转移到S3服务:
@api_view(['GET']) def get_image(request, image): """Get image link""" key = "media/" + str(image) s3 = boto3.client('s3', config=Config(signature_version='s3v4', region_name=settings.AWS_S3_REGION_NAME)) presigned_url = s3.generate_presigned_url( 'get_object', Params={'Bucket': settings.AWS_STORAGE_BUCKET_NAME, 'Key': key}, ExpiresIn=3600 ) return redirect(presigned_url)
内容的提问来源于stack exchange,提问作者Bastien
相关产品推荐
相关产品推荐

