Django/Nginx-提供超过一定大小的媒体文件时,禁止出现错误403 [英] Django/Nginx - Error 403 Forbidden when serving media files over some size

查看:60
本文介绍了Django/Nginx-提供超过一定大小的媒体文件时,禁止出现错误403的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

用户上载图像时,图像存储在项目目录内的 media 文件夹中.问题在于,当他们希望在网站上看到它时,nginx对于大约3 Mb以上的图像会返回 403 Forbidden 错误.

When user uploads image, it is stored in media folder inside project directory. The problem is that when they want to see it on the website, nginx return 403 Forbidden error for images over approximately 3 Mb.

我将 nginx.conf client_max_body_size 设置为8M

http {

        ##
        # Basic Settings
        ##
        client_max_body_size 8M;
     ...

并且已经更改了 settings.py 中的内存大小:

And already changed memory size in settings.py:

FILE_UPLOAD_MAX_MEMORY_SIZE = 8388608

当我上传3 MB以下的图像时,没有问题,如果我上传3 MB以上的图像,则可以在 media 文件夹中看到它,但是会出现错误,而不是提供图像:

When I upload an image under 3 MB, there are no problems, if I upload image over 3 MB, I can see it inside media folder but the error is raised instead of serving image:

GET https://example.com/media/images/dom.jpg 403 (Forbidden)

我注意到3 MB以下的文件具有不同的权限:

I noticed that files under 3 MB have different permissions:

-rw-r--r-- 1 django www-data    4962 Jul 19 19:51 61682_3995232_IMG_01_0000.jpg.150x84_q85_crop.jpg
-rw-r--r-- 1 django www-data 1358541 Jul 20 09:32 byt.jpg
-rw------- 1 django www-data 3352841 Jul 20 09:32 dom.jpg
-rw-r--r-- 1 django www-data    5478 Jul 19 20:10 downloasd.jpeg.150x84_q85_crop.jpg
-rw-r--r-- 1 django www-data    3225 Jul  9 22:53 images.jpeg.100x56_q85_crop.jpg
-rw-r--r-- 1 django www-data    6132 Jul 19 20:00 NorthYorkHouse2.JPG.150x84_q85_crop.jpg

您知道问题出在哪里吗?

Do you know where is the problem?

查看

class NehnutelnostUploadImagesView(LoginRequiredMixin, ExclusiveMaklerDetailView, DetailView):
    template_name = "nehnutelnosti/nehnutelnost_image_upload.html"
    model = Nehnutelnost

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        form = ImageUploadForm(self.request.POST, self.request.FILES, nehnutelnost=self.object)
        if form.is_valid():
            nehnutelnost_image = form.save()
            images_count = self.object.images.count()

            data = {'is_valid': True, 'row_html': image_row_renderer(nehnutelnost_image, self.request),
                    'name': nehnutelnost_image.image.name, 'url': nehnutelnost_image.image.url,}
        else:
            images_count = self.object.images.count()

            data = {'is_valid': False, 'errors': form.errors, 'images_count': images_count}
        return JsonResponse(data)

    def get_context_data(self, **kwargs):
        context = super(NehnutelnostUploadImagesView, self).get_context_data(**kwargs)
        context['images'] = self.object.images.all()
        context['podorys'] = self.object.podorys
        return context

我们使用 https://github.com/blueimp/jQuery-File-Up插件即可上传图片.

We use https://github.com/blueimp/jQuery-File-Upload plugin to upload images.

$(function () {

            $(".js-upload-photos").click(function () {
                $("#fileupload").click();
            });

            $("#fileupload").fileupload({
                dataType: 'json',
                sequentialUploads: true, /* 1. SEND THE FILES ONE BY ONE */
                start: function (e) {  /* 2. WHEN THE UPLOADING PROCESS STARTS, SHOW THE MODAL */
                    $(".modal").modal().show();
                },
                stop: function (e) {  /* 3. WHEN THE UPLOADING PROCESS FINALIZE, HIDE THE MODAL */
                    $(".modal").modal().hide();
                    $(".modal-backdrop").hide();

                },
                {#                TODO Chrome bug?#}
                progressall: function (e, data) {  /* 4. UPDATE THE PROGRESS BAR */
                    var progress = parseInt(data.loaded / data.total * 100, 10);
                    var strProgress = progress + "%";
                    $(".progress-bar").css({"width": strProgress});
                    $(".progress-bar").text(strProgress);
                },
                done: function (e, data) {
                    if (data.result.is_valid) {

                        $(".gridly").prepend(
                            data.result.row_html
                        )


                    }
                    var message = data.result.message;
                    addMessage('success', message);
                    var errors = data.result.errors;
                    if (errors) {
                        $.each(errors, function (fieldname, error_messages) {
                            $.each(error_messages, function (_, message) {
                                addMessage('danger', message);
                            })
                        })
                    }
                    var images_count_span = $('#images_count');
                    var images_count = data.result.images_count;
                    images_count_span.text(' - ' + images_count);
                    makegrid();

                }

            });

推荐答案

来自

默认情况下,如果上传的文件小于2.5兆字节,则Django会将上传的所有内容保存在内存中.

By default, if an uploaded file is smaller than 2.5 megabytes, Django will hold the entire contents of the upload in memory.

更具体地说,这意味着较小的文件使用 MemoryFileUploadHandler ,而较大的文件则使用

In more concrete terms, it means smaller files use the MemoryFileUploadHandler while larger files use the TemporaryFileUploadHandler. The latter uses tempfile to create a temporary file with user-only access.

在完成所有形式和模型验证以及所有内容之后,实际的保存是通过 FileSystemStorage._save 方法执行的.此时,文件仍然是 TemporaryUploadedFile InMemoryUploadedFile ,具体取决于文件的大小.

After going through all form and model validation and everything, the actual saving is performed by FileSystemStorage._save method. At this point, the file is still either a TemporaryUploadedFile or a InMemoryUploadedFile depending on its size.

现在,TemporaryUploadedFile是由 tempfile 创建的,具有纯用户权限的实际文件.

Now, a TemporaryUploadedFile is an actual file, created by tempfile, with user-only permissions.

save方法的作用很聪明:如果给定一个临时文件(即 if hasattr(content,'temporary_file_path')),它将移动它而不是复制它.这意味着它保留其仅用户权限,并且 www-data 仍然不可读.

The save method does the smart thing: if given a temporary file (namely, if hasattr(content, 'temporary_file_path')), it moves it instead of copying it. This means it keeps its user-only permissions and remains unreadable by www-data.

InMemoryUploadedFile不会出现此问题,InMemoryUploadedFile只会使用该进程具有的任何默认权限(在您的情况下,对用户和组都进行读/写操作).

The problem doesn't show up with InMemoryUploadedFile, which will simply use whatever default permissions the process has (in your case, read/write for both user and group).

如何解决?

如果需要,存储对象可以设置权限.对于默认存储对象,可以使用 进行设置FILE_UPLOAD_PERMISSIONS .在这里,

The storage object can set the permissions if so requested. For the default storage object, you can set this using FILE_UPLOAD_PERMISSIONS. Here,

FILE_UPLOAD_PERMISSIONS=0o640

...应该可以解决问题.

…should do the trick.

(对于django用户为R/W,对于nginx为只读)

(that's R/W for django user and read-only for nginx)

这篇关于Django/Nginx-提供超过一定大小的媒体文件时,禁止出现错误403的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆