我想使用django-channels上传文件和图像,但我不知道从哪里开始。似乎没有太多关于 websockets 和文件/图像上传的文档。有任何想法吗?
问问题
6714 次
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 回答