6

我想使用django-channels上传文件和图像,但我不知道从哪里开始。似乎没有太多关于 websockets 和文件/图像上传的文档。有任何想法吗?

4

3 回答 3

3

我也遇到了同样的问题,我通过上传 S3 存储桶中的图像/文件解决了这个问题。我们只需要解码base64代码并上传文件并将URL返回给websocket。我们还可以通过提供文件类型来提供图像的预览。

def file_upload(self, data):
    # Convert decode the base64 data 
    file = base64.b64decode(data['data']['content'].split(',')[-1])
    filename = data['data']['filename']
    type = data['data']['type']
    AWS_ACCESS_KEY_ID = getattr(settings, "AWS_S3_ACCESS_KEY_ID")
    AWS_SECRET_ACCESS_KEY = getattr(settings, "AWS_S3_SECRET_ACCESS_KEY")
    bucket_name = getattr(settings, "AWS_STORAGE_BUCKET_NAME")
    conn = boto.connect_s3(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
    bucket = conn.get_bucket(bucket_name)
    k = Key(bucket)
    k.key = getattr(settings, "AWS_CHAT_DIR") + '/' + filename
    k.set_metadata('Content-Type', type)
    k.set_contents_from_string(file)
    url = 'https://' + getattr(settings, "AWS_BUCKET_URL") + '/' + k.key
    message = url
    content = {
        'command': 'new_message',
        'message': self.message_to_json(message)
    }
    return self.send_chat_message(content)
于 2019-04-15T06:10:49.673 回答
2

唯一真正做到这一点的方法是使用 Channels 2,因为消费者会在会话期间持续存在,并且您可以将文件对象作为实例变量放在其上。

您可以看到我如何使用文件字段并首先在其上发送一些初始化参数。我拔出了重要的部分:

// Some class setup before this

// File field object
this.file = field.files[0];
init_params.action = 'prepare';
init_params.file_name = this.file.name;
init_params.file_size = this.file.size;

// This is a wrapper I have that gets a websocket. 
// The callback is called on connect. It sends the initialization parameters.
var ws = get_websocket(url, function(){
    this.send(JSON.stringify(init_params));
});

// After the initialization params are sent this is called with 0 as a parameter. 
// As the web server oks each chunk this is called with the next offset to send. chunk_size needs to be set somewhere.
var load_data = function(index) {
    var end =  index + this.chunk_size;
    if (index >= this.file.size)
        return;
    if (end > this.file.size)
        end = this.file.size;
    ws.send(this.file.slice(index, end));
}.bind(this);

ws.onmessage = function(msg) {
    var message = JSON.parse(msg.data);
    switch (message.action) {
        case 'progress':
            // This is called each time a chunk is written
            load_data(message.file_size);
            break;
        case 'ready':
            // This comes in to kick everything off
            load_data(0);
            break;
        case 'complete':
            // Handle complete
            break;
            }
        };
    }.bind(this);

在消费者中,我们检查它是否是文本数据,如果是,我们将其作为 JSON 处理以设置文件。如果它的二进制数据我们像这样写出每个块。

    async def handle_json(self, message):
         self.session = {
             # Set up file object and attributes
         }

    async def handle_chunk(self, message, **kwargs):
        upload_size = self.session.get('upload_size')
        temp_destination = self.session.get('upload_file')

        if not upload_size or not temp_destination:
            return self.error('Invalid request. Please try again.')

        self.session['upload_file'].write(message)
        size = self.session['upload_file'].tell()

        percent = round((size / upload_size) * 100)
        await self.send_json({
            'action': 'progress',
            'percent': percent,
            'file_size': size
        })

        if size >= upload_size:
            self.session['upload_file'].flush()
            file_name = await self.handle_complete(self.session['upload_file'])

            await self.send_json({
                'action': 'complete',
                'file_size': size,
                'file_name': file_name
            }, close=True)
于 2018-05-06T19:17:00.157 回答
1

简单的方法是使用 FileReader。在客户端,您将拥有以下代码。

//connect the websocket with server
var client = new WebSocket('ws://hostname')

//now get the base64 src for image for it i have 
  written a function.

function toDataURL(file, callback) {
    var reader = new FileReader();
    reader.onload = function () {
        var dataURL = reader.result;
        callback(dataURL);
    }
    reader.readAsDataURL(file);
}

document.getElementById('image').addEventListener('change', function(event){
    var files = event.target
    var file = files[0];
    toDataURL(file, function(dataURL){
    client.send(JSON.stringify({
        'command':'new_file', 
        'dataURL': dataURL
    }))
    })
})

这会将dataURL发送给您的消费者,然后您可以从那里将其发送给组,即发送给所有用户,并且可以将此dataURL用作图像的src以在浏览器上显示图像:)

例如:

<img src=dataURL>

您可以使用 javascript 函数创建它,例如您可以使用 document.createElement('img') 并使用 javascript 将 src 作为 dataURL 提供。

于 2021-04-16T11:22:13.867 回答