Safari

时间:2018-01-07 00:32:55

标签: python django python-3.x file-upload safari

我在Mac OS X上运行最新的Django 2版本(Python3.6)下的测试服务器。我的应用程序似乎在Safari 11.0.2和Chrome(版本63)上运行良好,除了一个令人讨厌的细节。我有这个文件上传表单:

class BulkForm(AssemblyForm):  # AssemblyForm itself defines a Char field.
    file = forms.FileField(required=True, label='Input file')

这是由以下视图处理的(我在本例中将其减少到最低限度):

def formtest(request):
    if request.method == 'POST':
        form = BulkForm(request.POST, request.FILES)
        if form.is_valid():
            upload = request.FILES['file']
            return HttpResponseRedirect(reverse('submissions'))
    bulk = BulkForm()
    return render(request, 'upload.html', {'bulk_form': bulk})

模板:

...
                <div class="tab-pane fade" id="bulk">
                    <div class="container my-4">
                        <form role="form" method="post"
                              enctype="multipart/form-data">
                            {% csrf_token %}
                            {{ bulk_form.as_p }}
                            <button type="submit" name="bulk-form"
                                    class="btn btn-primary bg-dark">
                                Submit
                            </button>
                        </form>
                    </div>
...

在Safari中,即使我尝试使用相同的文件,上传有时也会冻结:有时上传成功,有时会冻结。文件大小与卡住的可能性之间存在相关性。为了解决这个问题,我实现了自己的上传处理程序:

class SizeLimitedUploadedFile(uploadedfile.UploadedFile):
    def __init__(self, name, content_type, size, charset, content_type_extra=None):
        file = tempfile.NamedTemporaryFile(
            buffering=settings.FILE_UPLOAD_MAX_MEMORY_SIZE, delete=False,
            suffix=f'.upload.{name.split(".", 1)[1]}',
            dir=settings.FILE_UPLOAD_TEMP_DIR
        )
        super().__init__(file, file.name, content_type, 0, charset, content_type_extra)
        self.error = None

    def write(self, chunk: bytes) -> int:
        """
        :param chunk: bytes to write
        :return: the number of bytes written
        :raises FileSizeLimitReached: if file size reached
        """
        newsize = self.size + len(chunk)
        if newsize <= settings.FILE_UPLOAD_MAX_MEMORY_SIZE:
            self.file.write(chunk)
            self.size = newsize
            return len(chunk)
        self.error = FileSizeLimitReached
        raise FileSizeLimitReached

    def writelines(self, chunks: Iterable[bytes]):
        """
        :param chunks: bytes to write
        :raises FileSizeLimitReached: if file size reached
        """
        for chunk in chunks:
            self.write(chunk)


class TestFileUploadHandler(uploadhandler.FileUploadHandler):
    """
    File upload handler to stream uploads into memory (used for small files).
    """

    def new_file(self, *args, **kwargs):
        """
        Create the file object to append to as data are coming in.
        """
        print('creating new')
        super().new_file(*args, **kwargs)
        self.file = SizeLimitedUploadedFile(
            self.file_name, self.content_type, 0,
            self.charset, self.content_type_extra
        )
        self.counter = 0

    def receive_data_chunk(self, raw_data, start):
        self.counter += 1
        print(f'receiving batch {self.counter}')
        if self.file.error is None:
            with suppress(FileSizeLimitReached):
                self.file.write(raw_data)

    def file_complete(self, file_size):
        print('complete')
        self.file.seek(0)
        return self.file

然后我在settings.py中替换了默认的上传处理程序,并尝试多次上传同一个文件。当上传按预期终止时,我总是会看到对TestFileUploadHandler.receive_data_chunk的1250次通话。当它冻结时,计数器会保持1239-1245左右的呼叫。我只在Safari中看到过这种行为。 Chrome已经与内置处理程序以及我的自定义处理程序一起运行良好 - 它永远不会冻结。我已经尝试在网上搜索这个,到目前为止,最接近的打击是从2009年开始thread关于一个旧的WebKit错误。我跟着线程无济于事。我怎样才能解决这个问题?

更新

我已经对最新版本的Firefox和Opera进行了测试。两者都完美无缺。似乎这个问题与Safari隔离。

更新2

我在文件上传期间描述了Safari活动。无论出于何种原因,它有时会进入无限循环的重复页面渲染。

0 个答案:

没有答案