代码之家  ›  专栏  ›  技术社区  ›  Milano

django/nginx-当服务超过某个大小的媒体文件时,错误403被禁止

  •  5
  • Milano  · 技术社区  · 6 年前

    当用户上载图像时,它存储在 media 项目目录中的文件夹。问题是当他们想在网站上看到它时,nginx会返回 403 Forbidden 超过大约3 MB的图像出错。

    我设定 nginx.conf client_max_body_size 到800米

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

    已经改变了内存大小 settings.py :

    FILE_UPLOAD_MAX_MEMORY_SIZE = 8388608
    

    当我上传一个低于3MB的图片时,没有问题,如果我上传超过3MB的图片,我可以在里面看到。 媒体 文件夹,但出现错误而不是提供图像:

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

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

    -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
    

    你知道问题出在哪里吗?

    编辑:

    视图

    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-Upload 上载图像的插件。

    $(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();
    
                    }
    
                });
    
    1 回复  |  直到 6 年前
        1
  •  6
  •   spectras    6 年前

    来自 documentation :

    默认情况下,如果上载的文件小于2.5兆字节,Django将在内存中保存上载的全部内容。

    更具体地说,它意味着更小的文件使用 MemoryFileUploadHandler 当较大的文件使用 TemporaryFileUploadHandler . 后者使用 tempfile 创建一个只允许用户访问的临时文件。

    在完成所有表单和模型验证以及所有操作之后,实际保存由 FileSystemStorage._save 方法。此时,文件仍然是 TemporaryUploadedFile 或A InMemoryUploadedFile 取决于它的大小。

    现在,temporaryuploadedfile是一个实际文件,由 临时文件 ,仅具有用户权限。

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

    这个问题不会出现在InMemoryUploadFile中,它只使用进程拥有的任何默认权限(在您的情况下,对用户和组进行读/写)。

    如何修复?

    如果请求,存储对象可以设置权限。对于默认存储对象,可以使用 FILE_UPLOAD_PERMISSIONS . 在这里,

    FILE_UPLOAD_PERMISSIONS=0o640
    

    应该有技巧。

    (对于django用户是r/w,对于nginx是只读的)

    推荐文章