在Django中为生产提供图像文件的最佳做法是什么?我想用静态图像回复,并且我将我的Django应用程序部署到Heroku。
在效率或安全性方面使用django.middleware.security.SecurityMiddleware
而不是whitenoise.middleware.WhiteNoiseMiddleware
是否有任何明显的弊端?
与使用whitenoise相比,下面的代码是否效率低下?从settings.MEDIA_ROOT
提供与提供静态文件相同的图像吗?
img = os.path.join(settings.MEDIA_ROOT, filename)
try:
with open(img, "rb") as f:
return HttpResponse(f.read(), content_type="image/jpeg")
except IOError:
failedResponse = '{"detail": "No image found"}'
return HttpResponse(failedResponse)
答案 0 :(得分:9)
您的评论:
这里的whitenoise文档说我们不应该同时使用这两个中间件,我只是想知道是否有使用whitenoise而不是django.security的缺点 - Manan Mehta 30分钟前
不,它没有说 - 文档的那一部分是指MIDDLEWARE_CLASSES的顺序。你可以愉快地使用Whitenoise和Django的安全中间件。
以下文档摘录:
编辑您的settings.py文件并将WhiteNoise添加到MIDDLEWARE_CLASSES列表,除了Django的SecurityMiddleware之外的所有其他中间件:
MIDDLEWARE_CLASSES = [
# 'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
# ...
]
SnakeFcz建议强制Django提供静态服务并不是一个好主意 - Whitenoise软件包被设计为一种通过Django提供静态服务的高性能方法。请参阅heroku docs和Whitenoise docs。
回复你的编辑:
在Django中,静态是指您在开发期间创建的JS / CSS /图像,在部署应用程序时不会更改(保持静态)。媒体是用户上传的图像和视频,或生成的图像(例如缩略图)。
Django建议在STATIC_ROOT和MEDIA_ROOT目录中单独存储静态和媒体。然后,在生产中,您通常会在这些目录中为URL STATIC_URL和MEDIA_URL配置Web服务器。 Whitenoise通过正确提供来自这些文件夹的文件简化了一些事情,而无需配置Web服务器。
让Django正确提供图像(静态或媒体)的主要问题如下:
性能 - Django没有针对服务资产进行优化,因此它比通过Nginx / Apache等Web服务器提供服务要慢。大量的图像请求也会降低标准页面请求的速度,因为它们会排队并导致更长的响应时间。当您的网站很小时,这可能无关紧要,但是当您有网站流量时改变网站的工作方式很棘手!
缓存标头 - Django不知道在返回图像时会向图像添加缓存控制标头,而像Whitenoise这样的软件包会添加合理的缓存标头(最重要的是缓存过期,例如用户的缓存时间)浏览器挂在你的图像上。)
根据您返回图像的方式,Whitenoise可能会处理Django可能没有的其他标题:
媒体类型 - 浏览器需要知道如何处理他们所获得的响应,因此有一个名为Content-Type
的标头。使用上面的代码,您将每个文件作为图像返回 - 如果用户要求PNG会怎么样?
内容长度 - 浏览器使用内容长度(响应的大小)来显示进度条和其他优化(例如以块的形式读取响应)。
压缩 - 大多数浏览器和Web服务器(以及Whitenoise)都支持压缩方法,例如gzip或最近的brotli(由谷歌构建)。 Web服务器压缩文件(通常一次,然后缓存压缩文件)以最小化传输期间的带宽。根据图像和格式,您通常可以将图像压缩到其大小的60-70%左右。
在lena位图上演示:
❯ brew install gzip brotli
❯ gzip -k -v lena.bmp
lena.bmp: 18.3% -- replaced with lena.bmp.gz
❯ bro --input lena.bmp --output lena.bmp.bro
❯ ls -lh lena*
-rw-r--r--@ 1 alex staff 768K Feb 16 21:41 lena.bmp
-rw------- 1 alex staff 527K Feb 16 21:45 lena.bmp.bro
-rw-r--r--@ 1 alex staff 627K Feb 16 21:41 lena.bmp.gz
安全性 - 将静态资产提供给Web服务器的另一个原因是可能会出现安全漏洞!
我们假设视图中提供图片的代码如下,并且网址设置为static/<filename>
。
img = os.path.join(settings.MEDIA_ROOT, filename)
with open(img, "rb") as f:
return HttpResponse(f.read(), content_type="image/jpeg")
想象一下,如果恶意用户导航到yoursite.com/static//Users/alex/.ssh/id_rsa
。然后文件名变为/Users/alex/.ssh/id_rsa
:
filename = '/Users/alex/.ssh/id_rsa'
os.path.join(settings.MEDIA_ROOT, filename)
# '/Users/alex/.ssh/id_rsa'
然后视图读入您的Web服务器的私钥,并将其返回给恶意用户。哎呦!现在他们可以ssh到你的服务器。
Heroku上的媒体:
如果你要部署到Heroku,要记住的一件事就是他们的dynos工作方式。 Heroku dynos经常被创建和销毁(每次部署时,至少每天都有),因此您不能依赖文件系统来保持身边。您还可以同时运行两个或更多dynos - 这些是在数据中心的不同主机上运行的完全独立的容器,它们不共享文件系统。通常,如果您要处理用户上传的媒体,您将使用Django-storages在S3(AWS的存储服务)而不是文件系统上存储图像。您还可以将图像存储在数据库中,但这不能很好地扩展。有关设置为在S3上存储媒体的Django应用程序示例,请参阅https://github.com/eknuth/django-heroku-s3-bootstrap-demo。