将文件数据流式传输到MongoDB GridFS

2 投票
2 回答
2880 浏览
提问于 2025-04-18 10:07

我正在尝试在服务器上使用 Django 和 MongoEngine 将视频文件上传到 GridFS。

客户端:使用 JavaScript 来读取和分块文件,并通过 AJAX 将数据发送到服务器。

_upload : function() {
    chunk = self.file.slice( self.start, self.end );
    reader = new FileReader();
    reader.readAsDataURL( chunk );
    reader.onload = function(e) {
        this.request = new XMLHttpRequest();
        this.request.open( 'POST', '/ajax/video_upload/' );
        this.request.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
        this.request.overrideMimeType('application/octet-stream');
        this.request.send( JSON.stringify({ 'chunk': e.target.result, 'id' : self.file_id }) );
        this.request.onload = function() {

        if( self.start >= self.file_size && self.preventedOverflow ) {
        return;
        }

        self.start = self.end;
        self.end = self.end + self.chunkSize;

       self._upload();
    };
}

服务器端:

def uploadVideo(request):
if request.body and request.is_ajax:
    data = json.loads(request.body)
    m = Multimedia.objects.get( id = data['id'] )
    m.media.new_file()
    m.media.write( data['chunk'] )
    m.media.close()
    m.save()
    return HttpResponse()

错误:

ERROR:django.request:Internal Server Error: /ajax/video_upload/
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 115, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "/home/praveen/Desktop/gatherify/gatherify/../ajax/views.py", line 33, in uploadVideo
    m.media.write( data['chunk'] )
  File "/usr/local/lib/python2.7/dist-packages/mongoengine-0.8.7-py2.7.egg/mongoengine/fields.py", line 1172, in write
    self.newfile.write(string)
  File "build/bdist.linux-i686/egg/gridfs/grid_file.py", line 327, in write
    "order to write %s" % (text_type.__name__,))
TypeError: must specify an encoding for file in order to write unicode

我不知道如何指定编码,官方文档没有提到这方面的内容。 (http://mongoengine-odm.readthedocs.org/guide/gridfs.html)

另一个问题是,当我尝试在下一个 AJAX 请求中写入下一个数据块时,我遇到了一个错误:

GridFSError: This document already has a file. Either delete it or call replace to overwrite it

任何帮助都非常感谢。谢谢 :)

2 个回答

0

1. 你需要用utf-8格式来写数据。

2. 在写完第一部分数据后,不要关闭从newfile得到的GridOut实例。

3. 每次上传新文件时,都应该创建一个新的greenlet。

4. 写完一部分数据后,要进行一次“暂停”,也就是yield。

5. 发送确认信息(ack)以接收下一部分数据,同时还要发送一个“id”来识别这个greenlet。

6. 唤醒greenlet,并发送新的数据部分。

7. 如果没有数据部分了,就发送“文件结束”的信息。

8. 现在可以关闭GridOut了。

9. 退出greenlet。

2

在把 data['chunk'] 字符串写入 FileField 之前,先对它进行编码。

m.media.new_file()
m.media.write( data['chunk'].encode("UTF-8") )
m.media.close()

关于你的第二个问题,你已经在 gridfs 中创建了一个文件。就像错误信息所说的,你需要用 m.media.delete() 删除它,或者用 m.media.replace(<一个新的 gridfs 条目>) 来替换它。如果你想要追加内容,可能需要先用 m.media.get() 获取文件内容作为字符串,然后把新的部分追加到这个字符串里,最后再创建一个新的 m.media gridfs 文件。你不能直接编辑 gridfs 中的内容。

撰写回答