简体   繁体   English

在Django中提供静态文件的最佳实践

[英]Best practice to serve static files in Django

What is the best practice to serve image files in Django for production? 在Django中为生产提供图像文件的最佳做法是什么? I want to respond with static images and I'm deploying my Django app to Heroku. 我想用静态图像回复,我正在将我的Django应用程序部署到Heroku。

Are there any significant drawbacks of using django.middleware.security.SecurityMiddleware instead of whitenoise.middleware.WhiteNoiseMiddleware in terms of efficiency or security? 在效率或安全性方面使用django.middleware.security.SecurityMiddleware而不是whitenoise.middleware.WhiteNoiseMiddleware有任何明显的缺点吗?

Is the code below inefficient compared to using whitenoise? 与使用whitenoise相比,下面的代码是否效率低下? Is serving an image from settings.MEDIA_ROOT the same as serving a static file? 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)

Your comment: 你的评论:

The whitenoise documentation here says that we should not use both the middlewares and I just wanted to know if there was a drawback of using whitenoise over django.security – Manan Mehta 30 mins ago 这里的whitenoise文档说我们不应该同时使用这两个中间件,我只是想知道是否有使用whitenoise而不是django.security的缺点 - Manan Mehta 30分钟前

No, it doesn't say that - that section of the documentation refers to the order of MIDDLEWARE_CLASSES. 不,它没有说 - 文档的那一部分是指MIDDLEWARE_CLASSES的顺序。 You can happily use Whitenoise with Django's security middleware. 你可以愉快地使用Whitenoise和Django的安全中间件。

Excerpt from the docs below: 摘自以下文档:

Edit your settings.py file and add WhiteNoise to the MIDDLEWARE_CLASSES list, above all other middleware apart from Django's SecurityMiddleware: 编辑您的settings.py文件并将WhiteNoise添加到MIDDLEWARE_CLASSES列表,除了Django的SecurityMiddleware之外的所有其他中间件:

MIDDLEWARE_CLASSES = [  
    # 'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',  
    # ...
]

SnakeFcz's recommendation to force Django to serve static is not a good idea - the Whitenoise package is designed as a high performance method to serve static through Django. SnakeFcz建议强制Django提供静态服务并不是一个好主意 - Whitenoise软件包被设计为一种通过Django提供静态服务的高性能方法。 See the heroku docs and the Whitenoise docs . 请参阅heroku文档Whitenoise文档


Reply to your edit: 回复你的编辑:

In Django, static refers to things like JS/CSS/images that you create during development that don't change (remains static ) when your app is deployed. 在Django中,静态是指在开发过程中创建的JS / CSS /图像,在部署应用程序时不会更改(保持静态 )。 Media are things like user uploaded images and video, or generated images (eg thumbnails). 媒体是用户上传的图像和视频,或生成的图像(例如缩略图)。

Django recommends storing static and media separately, in STATIC_ROOT and MEDIA_ROOT directories. Django建议在STATIC_ROOT和MEDIA_ROOT目录中单独存储静态和媒体。 Then in production you typically configure a web server at these directories for the URLs STATIC_URL and MEDIA_URL. 然后,在生产中,您通常会在这些目录中为URL STATIC_URL和MEDIA_URL配置Web服务器。 Whitenoise simplifies things a bit by serving files from these folders correctly, without having to configure a web server. Whitenoise通过正确提供来自这些文件夹的文件简化了一些事情,而无需配置Web服务器。

The main concerns for getting Django to serve images correctly (static or media) are as follows: 让Django正确提供图像(静态或媒体)的主要问题如下:

  • Performance - Django is not optimised for serving assets, so it'll be slower than serving through a web server such as Nginx/Apache. 性能 - Django没有针对服务资产进行优化,因此它比通过Nginx / Apache等Web服务器提供服务要慢。 Lots of image requests will also slow down standard page requests, because they'll queue up and cause a longer response time. 大量的图像请求也会降低标准页面请求的速度,因为它们会排队并导致更长的响应时间。 This might not matter when your website is small, but changing the way your website works when you have traffic is tricky! 当您的网站很小时,这可能无关紧要,但是当您有网站时改变网站的工作方式是棘手的!

  • Caching headers - Django doesn't know to add cache-control headers to images when they're returned, whereas packages like Whitenoise add sensible caching headers (the most important being the cache expiry, eg how long for user's browsers to hang onto your images). 缓存标头 - Django不知道在返回时为图像添加缓存控制标头,而像Whitenoise这样的软件包会添加合理的缓存标头(最重要的是缓存过期,例如用户的浏览器挂在图像上多长时间) )。

There are some other headers that Whitenoise handles that Django might not, depending on the way you return an image: 根据返回图像的方式,Whitenoise可能会处理Django可能没有的其他标头:

  • Media types - browsers need to know how to deal with the response they're getting, so there's a header called Content-Type . 媒体类型 - 浏览器需要知道如何处理他们获得的响应,因此有一个名为Content-Type的标头。 With your code above, you're returning every file as an image - what if the user asks for a PNG? 使用上面的代码,您将每个文件作为图像返回 - 如果用户要求PNG,该怎么办?

  • Content length - browsers use the content length (size of the response) to show progress bars, and other optimisation (such as reading the response in chunks). 内容长度 - 浏览器使用内容长度(响应的大小)来显示进度条和其他优化(例如以块的形式读取响应)。

  • Compression - most browsers and web servers (and Whitenoise) support compression methods such as gzip or more recently brotli (built by google). 压缩 - 大多数浏览器和Web服务器(以及Whitenoise)都支持压缩方法,例如gzip或最近的brotli(由谷歌构建)。 The web server compresses the file (usually once, and then the compressed file is cached) to minimise bandwidth during transfer. Web服务器压缩文件(通常一次,然后缓存压缩文件)以最小化传输期间的带宽。 Depending on the image and format, you can often compress images down to around 60-70% of their size. 根据图像和格式,您通常可以将图像压缩到其大小的60-70%左右。

    Demo on lena bitmap: 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 
  • Security - another reason to leave serving static assets to the web server is the potential for security exploits! 安全性 - 将静态资产提供给Web服务器的另一个原因是安全漏洞的可能性!

    Let's assume the code in your view to serve images is as follows, and the url is set up at static/<filename> . 我们假设视图中用于提供图像的代码如下,并且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") 

    Imagine if a malicious user navigated to yoursite.com/static//Users/alex/.ssh/id_rsa . 想象一下,如果恶意用户导航到yoursite.com/static//Users/alex/.ssh/id_rsa Then filename becomes /Users/alex/.ssh/id_rsa : 然后filename变为/Users/alex/.ssh/id_rsa

     filename = '/Users/alex/.ssh/id_rsa' os.path.join(settings.MEDIA_ROOT, filename) # '/Users/alex/.ssh/id_rsa' 

    Then the view reads in your web server's private key, and return it to the malicious user. 然后,视图将读入您的Web服务器的私钥,并将其返回给恶意用户。 Whoops! 哎呦! Now they can ssh into your server. 现在他们可以ssh到你的服务器。


Media on Heroku: Heroku上的媒体:

One thing to bear in mind if you're deploying to Heroku is the way their dynos work. 如果你要部署到Heroku,要记住的一件事就是他们的dynos工作方式。 Heroku dynos are created and destroyed quite often (every time you deploy, and at least every day) so you can't rely on the file system to stay around. Heroku dynos经常被创建和销毁(每次部署时,至少每天都有),因此您不能依赖文件系统来保持身边。 You can also run two or more dynos at once - these are completely separate containers run on different hosts in a data centre, they don't share a filesystem. 您还可以同时运行两个或更多dynos - 这些是在数据中心的不同主机上运行的完全独立的容器,它们不共享文件系统。 Usually if you want to handle user uploaded media, you'll use Django-storages to store images on S3 (AWS's storage service) instead of the filesystem. 通常,如果您想处理用户上传的媒体,您将使用Django存储将图像存储在S3(AWS的存储服务)而不是文件系统上。 You could also store images in your database, but that doesn't scale as nicely. 您还可以将图像存储在数据库中,但这不能很好地扩展。 See https://github.com/eknuth/django-heroku-s3-bootstrap-demo for an example Django app set up to store media on S3. 有关设置为在S3上存储媒体的Django应用程序示例,请参阅https://github.com/eknuth/django-heroku-s3-bootstrap-demo

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM