您的评论:
这里的whitenoise文档说我们不应该同时使用中间件,我只想知道使用whitenoise是否存在缺点,相对于django.security——Manan Mehta 30分钟之前
不,它没有说那个-文档中的那一节是指MIDDLEWARE_CLASSES的顺序。你可以放心地将Whitenoise与Django的安全中间件一起使用。
下面是文档中的摘录:
编辑您的settings.py文件,并将WhiteNoise添加到MIDDLEWARE_CLASSES列表中,在除Django的SecurityMiddleware之外的所有其他中间件之上:
MIDDLEWARE_CLASSES = [
'whitenoise.middleware.WhiteNoiseMiddleware',
]
SnakeFcz的强制让Django提供静态文件的建议不是一个好主意 - Whitenoise包是专门为通过Django提供静态文件设计的高性能方法。请参见
heroku文档 和
Whitenoise文档。
在Django中,静态文件是指像JS/CSS/images这样的你在开发期间创建的不会改变(保持静态)的东西。媒体则是像用户上传的图像和视频或生成的图像(例如缩略图)之类的东西。
Django建议将静态文件和媒体分别存储在STATIC_ROOT和MEDIA_ROOT目录中。然后,在生产中,您通常会在这些目录下配置Web服务器以获取URL STATIC_URL和MEDIA_URL。Whitenoise可以通过正确地从这些文件夹中提供文件来简化这些过程,而无需配置Web服务器。
使Django能够正确提供图像(静态或媒体)的主要问题如下:
- 性能 - Django未经过优化,因此比通过诸如Nginx / Apache之类的Web服务器提供服务慢。大量的图片请求也会减慢标准页面请求的速度,因为它们会排队并导致更长的响应时间。当您的网站很小时,这可能无关紧要,但在拥有流量时更改网站工作方式会很棘手!
- 缓存标头 - 当返回图像时,Django不知道添加缓存控制标头,而像Whitenoise这样的包添加了明智的缓存标头(最重要的是缓存到期时间,例如用户浏览器保留图像的时间)。
Whitenoise处理的其他一些标头可能取决于您返回图像的方式:
- 媒体类型 - 浏览器需要知道如何处理返回的响应,因此有一个名为Content-Type的标头。使用您上面的代码,您将每个文件都返回为图像 - 如果用户请求PNG呢?
- 内容长度 - 浏览器使用内容长度(响应大小)来显示进度条和其他优化(例如分块读取响应)。
- 压缩 - 大多数浏览器和Web服务器(以及Whitenoise)支持压缩方法,例如Gzip或最近由Google开发的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服务器的另一个原因是潜在的安全漏洞!
假设您视图中用于提供图像的代码如下,并且该URL设置为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)
然后视图读取您的Web服务器私钥,并将其返回给恶意用户。哎呀!现在他们可以ssh进入您的服务器。
Heroku上的媒体:
如果您要部署到Heroku,请记住他们的dynos工作方式。Heroku dynos经常创建和销毁(每次部署时,至少每天一次),因此您无法依赖文件系统来保留数据。您也可以同时运行两个或多个dynos - 这些是完全独立的容器,在数据中心的不同主机上运行,它们不共享文件系统。通常,如果您想处理用户上传的媒体文件,则会使用Django-storages将图像存储在S3(AWS的存储服务)而不是文件系统上。您还可以将图像存储在数据库中,但这样做可能无法很好地扩展。请参见https://github.com/eknuth/django-heroku-s3-bootstrap-demo,了解一个设置为将媒体存储在S3上的示例Django应用程序。