vue+django實(shí)現(xiàn)一對(duì)一聊天功能

vue+django實(shí)現(xiàn)一對(duì)一聊天和消息推送的功能。主要是通過websocket,由于Django不支持websocket吃挑,所以我使用了django-channels〗至ⅲ考慮到存儲(chǔ)量的問題舶衬,我并沒有把聊天信息存入數(shù)據(jù)庫,服務(wù)端的作用相當(dāng)于一個(gè)中轉(zhuǎn)站几晤。我只講述實(shí)現(xiàn)功能的結(jié)構(gòu)性代碼约炎,具體的實(shí)現(xiàn)還請(qǐng)大家看源代碼植阴。

效果展示

1.gif

實(shí)現(xiàn)過程

后端

首先蟹瘾,我們需要先定義websocket的兩條連接路徑。ws/chat/xxx/xxx指代聊天組)這條路徑是當(dāng)聊天雙方都進(jìn)入同一個(gè)聊天組以后掠手,開始聊天的路徑憾朴。push/xxx/xxx指代用戶名)這條是指當(dāng)有一方不在聊天組,另一方的消息將通過這條路徑推送給對(duì)方喷鸽。ws/chat/xxx/只有雙方都進(jìn)入聊天組以后才開啟众雷,而push/xxx/是自用戶登錄以后,直至退出都開啟的。

websocket_urlpatterns = [
    url(r'^ws/chat/(?P<group_name>[^/]+)/$', consumers.ChatConsumer),
    url(r'^push/(?P<username>[0-9a-z]+)/$', consumers.PushConsumer),
]

我們采用user_a的id加上下劃線_加上user_b的id的方式來命名聊天組名砾省。其中id值從小到大放置鸡岗,例如:195752_748418。當(dāng)用戶通過ws/chat/group_name/的方式向服務(wù)端請(qǐng)求連接時(shí)编兄,后端會(huì)把這個(gè)聊天組的信息放入一個(gè)字典里轩性。當(dāng)連接關(guān)閉時(shí),就把聊天組從字典里移除狠鸳。

class ChatConsumer(AsyncJsonWebsocketConsumer):
    chats = dict()

    async def connect(self):
        self.group_name = self.scope['url_route']['kwargs']['group_name']

        await self.channel_layer.group_add(self.group_name, self.channel_name)
        # 將用戶添加至聊天組信息chats中
        try:
            ChatConsumer.chats[self.group_name].add(self)
        except:
            ChatConsumer.chats[self.group_name] = set([self])

        #print(ChatConsumer.chats)
        # 創(chuàng)建連接時(shí)調(diào)用
        await self.accept()


    async def disconnect(self, close_code):
        # 連接關(guān)閉時(shí)調(diào)用
        # 將關(guān)閉的連接從群組中移除
        await self.channel_layer.group_discard(self.group_name, self.channel_name)
        # 將該客戶端移除聊天組連接信息
        ChatConsumer.chats[self.group_name].remove(self)
        await self.close()

接著揣苏,我們需要判斷連接這個(gè)聊天組的用戶個(gè)數(shù)。當(dāng)有兩個(gè)用戶連接這個(gè)聊天組時(shí)件舵,我們就直接向這個(gè)聊天組發(fā)送信息卸察。當(dāng)只有一個(gè)用戶連接這個(gè)聊天組時(shí),我們就通過push/xxx/把信息發(fā)給接收方铅祸。

 async def receive_json(self, message, **kwargs):
        # 收到信息時(shí)調(diào)用
        to_user = message.get('to_user')
        # 信息發(fā)送
        length = len(ChatConsumer.chats[self.group_name])
        if length == 2:
            await self.channel_layer.group_send(
                self.group_name,
                {
                    "type": "chat.message",
                    "message": message.get('message'),
                },
            )
        else:
            await self.channel_layer.group_send(
                to_user,
                {
                    "type": "push.message",
                    "event": {'message': message.get('message'), 'group': self.group_name}
                },
            )


    async def chat_message(self, event):
        # Handles the "chat.message" event when it's sent to us.
        await self.send_json({
            "message": event["message"],
        })


# 推送consumer
class PushConsumer(AsyncWebsocketConsumer):

    async def connect(self):
        self.group_name = self.scope['url_route']['kwargs']['username']

        await self.channel_layer.group_add(
            self.group_name,
            self.channel_name
        )

        await self.accept()

    async def disconnect(self, close_code):
        await self.channel_layer.group_discard(
            self.group_name,
            self.channel_name
        )

        # print(PushConsumer.chats)

    async def push_message(self, event):
        print(event)
        await self.send(text_data=json.dumps({
            "event": event['event']
        }))

前端

前端實(shí)現(xiàn)websocket就比較簡(jiǎn)單了坑质。就是對(duì)websocket進(jìn)行初始化,定義當(dāng)websocket連接个少、關(guān)閉和接收消息時(shí)要執(zhí)行哪些動(dòng)作洪乍。

<script>
  export default {
    name : 'test',
    data() {
      return {
        websock: null,
      }
    },
    created() {
      this.initWebSocket();
    },
    destroyed() {
      this.websock.close() //離開路由之后斷開websocket連接
    },
    methods: {
      initWebSocket(){ //初始化weosocket
        const wsuri = "ws://127.0.0.1:8080";
        this.websock = new WebSocket(wsuri);
        this.websock.onmessage = this.websocketonmessage;
        this.websock.onopen = this.websocketonopen;
        this.websock.onerror = this.websocketonerror;
        this.websock.onclose = this.websocketclose;
      },
      websocketonopen(){ //連接建立之后執(zhí)行send方法發(fā)送數(shù)據(jù)
        let actions = {"test":"12345"};
        this.websocketsend(JSON.stringify(actions));
      },
      websocketonerror(){//連接建立失敗重連
        this.initWebSocket();
      },
      websocketonmessage(e){ //數(shù)據(jù)接收
        const redata = JSON.parse(e.data);
      },
      websocketsend(Data){//數(shù)據(jù)發(fā)送
        this.websock.send(Data);
      },
      websocketclose(e){  //關(guān)閉
        console.log('斷開連接',e);
      },
    },
  }
</script>

參考文章

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市夜焦,隨后出現(xiàn)的幾起案子壳澳,更是在濱河造成了極大的恐慌,老刑警劉巖茫经,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件巷波,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡卸伞,警方通過查閱死者的電腦和手機(jī)抹镊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荤傲,“玉大人垮耳,你說我怎么就攤上這事∷焓颍” “怎么了终佛?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)雾家。 經(jīng)常有香客問我铃彰,道長(zhǎng),這世上最難降的妖魔是什么芯咧? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任牙捉,我火速辦了婚禮竹揍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘邪铲。我一直安慰自己芬位,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布带到。 她就那樣靜靜地躺著晶衷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪阴孟。 梳的紋絲不亂的頭發(fā)上晌纫,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音永丝,去河邊找鬼锹漱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛慕嚷,可吹牛的內(nèi)容都是我干的哥牍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼喝检,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼嗅辣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起挠说,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤澡谭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后损俭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛙奖,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年杆兵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了雁仲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡琐脏,死狀恐怖攒砖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情日裙,我是刑警寧澤吹艇,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站阅签,受9級(jí)特大地震影響掐暮,放射性物質(zhì)發(fā)生泄漏蝎抽。R本人自食惡果不足惜政钟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一路克、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧养交,春花似錦精算、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鱼辙,卻和暖如春廉嚼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背倒戏。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工怠噪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人杜跷。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓傍念,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親葛闷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子憋槐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容