從前端到后臺(tái):一個(gè)聊天項(xiàng)目帶你擼全棧

差不多花了整整兩個(gè)星期,終于把這個(gè)聊天APP的后臺(tái)架構(gòu)搭建出來了跃惫。雖然花的時(shí)間比較多叮叹,但這也是我第一次寫后臺(tái),其實(shí)也并沒有想象中的那么難爆存,但也還是很折騰蛉顽,尤其是在數(shù)據(jù)庫這一塊,幾乎全部都是英文文檔(看得都只想**)先较。

項(xiàng)目概述

該聊天App高仿iOS端的微信携冤,當(dāng)然沒這么復(fù)雜,目前已實(shí)現(xiàn)功能有:

  • 用戶注冊闲勺、登錄曾棕、注銷功能;
  • 自動(dòng)緩存已登錄用戶菜循,關(guān)閉瀏覽器窗口失效翘地;
  • 聊天室:所以在線用戶之間聊天;
  • 與在線用戶之間聊天癌幕;
  • 獲取所有在線用戶衙耕;
  • 獲取好友列表;
  • 添加好友:后臺(tái)接口已完成勺远,前端目前尚未實(shí)現(xiàn)橙喘。

現(xiàn)在幾乎每天都在更新,爭取把它做得更像一個(gè)正規(guī)的聊天應(yīng)用胶逢。不過由于該應(yīng)用是基于Web頁面的厅瞎,用戶體驗(yàn)和數(shù)據(jù)持久化等諸多方面肯定沒法跟客戶端應(yīng)用相比。

前端Web界面

前端界面在一個(gè)多月前就已經(jīng)差不多寫出來了初坠,苦于一直沒有后臺(tái)接口(API)的支持和簸,所以僅僅只是一個(gè)界面展示,并無實(shí)際聊天的功能碟刺。

對前端我就不做深入的介紹了比搭,主要是基于Vue來實(shí)現(xiàn)的。而且對于一個(gè)前端開發(fā)者來說南誊,后臺(tái)實(shí)現(xiàn)可能更具有挑戰(zhàn)性身诺。

后臺(tái)實(shí)現(xiàn)

為了實(shí)現(xiàn)真實(shí)的聊天功能,我決定自己來搭建后臺(tái)抄囚,這也是我第一次寫后臺(tái)霉赡。整個(gè)后臺(tái)應(yīng)用基于Node.js平臺(tái),采用express模塊來搭建HTTP服務(wù)器幔托,聊天功能采用WebSocket實(shí)現(xiàn)穴亏,數(shù)據(jù)庫使用的是MongoDB

主要使用的技術(shù)棧包括:Node.js重挑、express嗓化、express-sessionexpress-ws谬哀、mongodb刺覆、mongoose

后臺(tái)邏輯分析

初次寫后臺(tái)史煎,最難的可能就是架構(gòu)了谦屑,因?yàn)槟阋獙φ麄€(gè)應(yīng)用的需求、實(shí)現(xiàn)的功能篇梭、數(shù)據(jù)的模型等有一個(gè)清晰的思路邏輯氢橙。我可能也就是在這方面花的時(shí)間是最多的,總是不知道該如何下手恬偷。很多次都是寫著寫著就寫不下去了悍手,因?yàn)檫壿嬓胁煌恕?/p>

遇到的問題和難點(diǎn)

  • 如何判斷用戶是否是登錄狀態(tài)?如何記住用戶的登錄狀態(tài)袍患?
  • 如何斷定當(dāng)前登錄的用戶是否成功連接了WebSocket服務(wù)器坦康?
  • 當(dāng)一個(gè)來自客戶端的websocket請求時(shí),如何判斷該用戶是否已登錄协怒?需要一個(gè)身份識(shí)別功能涝焙,否則誰都可以任意接入websockt服務(wù)器了。
  • HTTP服務(wù)器與WebSocket服務(wù)器之間如何并存孕暇?又如何交互仑撞?因?yàn)橹挥辛奶旃δ芎拖⑼扑凸δ苁褂?code>ws,其他所有的請求都是與http服務(wù)器通信妖滔。
  • ws服務(wù)器如何判斷消息的轉(zhuǎn)發(fā)目標(biāo)隧哮?如果目標(biāo)用戶不在線又如何處理?
  • 如何搭建數(shù)據(jù)庫座舍?對于初次接觸的人來說這也是個(gè)難題沮翔。
  • 如何連接和操作數(shù)據(jù)庫?起碼要基本的增刪改查曲秉。
  • 密碼加密問題采蚀,這同樣是一個(gè)很大的難題疲牵。

其實(shí)問題還有很多很多,這可能對于后臺(tái)開發(fā)人員來說都顯得小兒科榆鼠,但這些真是我開發(fā)過程中遇到的問題纲爸,當(dāng)然還不止如此。到目前為止妆够,有的問題已經(jīng)解決了识啦,有的問題仍未解決,或沒有找到更好的解決方案神妹。

其實(shí)颓哮,學(xué)習(xí)也就是一個(gè)發(fā)現(xiàn)問題,然后解決問題的過程鸵荠。當(dāng)你把一個(gè)一個(gè)的問題都解決之后冕茅,你也就在不知不覺中慢慢成長起來了。貴在堅(jiān)持腰鬼,也難在堅(jiān)持嵌赠。

模塊介紹

對于上面的問題,我也是自己網(wǎng)上找資料熄赡,目前主要引用到了這些模塊框架:

  • express:基本上是整個(gè)后臺(tái)應(yīng)用的支撐姜挺,HTTP和ws都是建立在此基礎(chǔ)之上。一個(gè)Node.js上很強(qiáng)大的東西彼硫,可以讓你快速創(chuàng)建一個(gè)Web應(yīng)用炊豪。
  • express-session:這個(gè)是express的插件,主要用來解決上面說到的判斷用戶是否登錄的問題拧篮。
  • express-ws:這也是一個(gè)express的插件词渤,用來構(gòu)件一個(gè)ws服務(wù)器。之前采用的是ws框架串绩,但與express交互性太差缺虐,不好在wshttp之間通信。
  • body-parser:一個(gè)express框架礁凡,主要用來解析POST請求發(fā)過來的數(shù)據(jù)高氮。
  • mongoose:一個(gè)用來操作mongodb數(shù)據(jù)庫的框架。還有一個(gè)叫做mongolass的框架顷牌,比這個(gè)量級(jí)要輕剪芍。

主目錄結(jié)構(gòu)

由于是第一次寫后臺(tái),后臺(tái)結(jié)構(gòu)分的并不是很清晰窟蓝。

  • index.js:入口文件罪裹,創(chuàng)建一個(gè)http服務(wù)器和一個(gè)ws服務(wù)器,并連接到數(shù)據(jù)庫。
  • model:該目錄主要寫一些與數(shù)據(jù)庫交互的代碼状共。
  • routes:這個(gè)目錄主要處理路由套耕,大部分的操作都是在該目錄下進(jìn)行的。

主要的架構(gòu)就是這樣口芍,基本操作都在routes目錄下箍铲,因?yàn)楹笈_(tái)也就是為前端寫接口。在routes目錄下又分了不同的子路由鬓椭,比如:frienduser关划、ws小染、message等,分別處理不同的請求贮折。

看起來很簡單裤翩,但做起來真的不容易,最可怕的是代碼量大了调榄,你會(huì)陷入一個(gè)大量重復(fù)代碼和無限回調(diào)的噩夢踊赠,我想大部分人都經(jīng)歷過js的回調(diào)噩夢。目前也只是有了個(gè)初步的邏輯架構(gòu)每庆,后面可能會(huì)根據(jù)需求的不同而變更筐带。代碼也需要優(yōu)化,有的自己一遍一遍寫起來就惡心缤灵。

兩個(gè)容易誤會(huì)的概念

本篇文章主要作個(gè)整體的介紹伦籍,因?yàn)樵揥eb應(yīng)用目前仍在開發(fā)中,很多功能還不確定腮出,等后面整個(gè)邏輯清晰了再作總結(jié)帖鸦。下面說兩個(gè)很經(jīng)典的問題,也是前端很容易誤會(huì)的問題胚嘲,至少我是誤會(huì)了很久作儿。

跨域

我的前端頁面是托管在GitHub上的,通過開啟靜態(tài)頁面的功能馋劈,可使用域名來訪問http://mohng.com/wchat-vue攻锰。而我的后臺(tái)是搭建在自己的服務(wù)器中的,所以自然就面臨了一個(gè)問題:跨域訪問侣滩。

在這之前口注,對跨域訪問是一知半解,不知道到底該如何解決這個(gè)問題君珠。這里要提出寝志,跨域訪問不是前端的問題,其實(shí)大部分都是后臺(tái)的問題。對于跨域材部,網(wǎng)上有兩種解決方案:JSONP和Ajax毫缆。對于JSONP沒什么研究,不作介紹乐导,好像也并不是很實(shí)用苦丁,這里主要介紹Ajax跨域的問題。

下面是我后臺(tái)解決跨域問題的方案:

app.use((req, res, next) => {
    res.set({
        // 跨域cookie 不能為通配符 *
        'Access-Control-Allow-Origin': 'http://localhost:8808',
        'Access-Control-Allow-Methods': 'GET,POST',
        // 跨域cookie必須為true
        'Access-Control-Allow-Credentials': true
    });
    next();
});

簡單的說一下物臂,跨域其實(shí)瀏覽器是可以正常的收到來自于服務(wù)的響應(yīng)旺拉,只是無法正確的解析。通過在服務(wù)器端對響應(yīng)頭寫入'Access-Control-Allow-Origin': '*''Access-Control-Allow-Methods': 'GET,POST'棵磷,瀏覽器才能正確的解析服務(wù)器的響應(yīng)蛾狗。記住是在服務(wù)器端對響應(yīng)頭的操作,我之前一直誤會(huì)是在前端的請求頭中寫入仪媒,現(xiàn)在想想有點(diǎn)傻逼了沉桌。

對于'Access-Control-Allow-Credentials': true,是用來處理跨域中cookie的問題算吩。因?yàn)槟J(rèn)情況下留凭,cookie是不允許在跨域訪問中傳輸?shù)摹R鉀Q這個(gè)問題偎巢,Access-Control-Allow-Origin的值就不能為通配符*蔼夜,并且前端通過Ajax發(fā)起請求時(shí)也要做處理。

$.ajax(url, {
    method: 'GET',
    xhrFields: {
        withCredentials: true
    },
    ...
})

Cookie

之前對Cookie的認(rèn)識(shí)一直就是一種類似于緩存的東西艘狭,但具體是做什么挎扰,怎么用,并不清楚巢音。這是要指出兩點(diǎn):

  • Cookie基本上都是由后臺(tái)來管理的遵倦,前端不需要任何操作
  • Cookie信息會(huì)在每次發(fā)起的請求中自動(dòng)攜帶

那么,這下就清晰多了官撼。如果你僅僅只是搞前端梧躺,基本上是用不到Cookie的。雖然也可以通過js代碼讀取到cookie數(shù)據(jù)傲绣,但大部分服務(wù)器都是禁用掉此操作掠哥,也就是讓你在前端無法通過js代碼讀取到cookie的內(nèi)容,讀取到的是空字符串秃诵。

因?yàn)?code>cookie是每次發(fā)起請求都會(huì)自動(dòng)攜帶的续搀,所以服務(wù)器就可以通過cookie來識(shí)別用戶的身份、是否處于登錄狀態(tài)等菠净,就像你進(jìn)入某個(gè)網(wǎng)站有時(shí)候會(huì)自動(dòng)識(shí)別你的身份并登錄禁舷。而cookie也是可以設(shè)置過期時(shí)間的彪杉,所以服務(wù)器端就可以控制你的身份多久失效牵咙,失效之后你就要重新登錄了派近。

你可以自己嘗試在瀏覽器的控制臺(tái)通過document.cookie來獲取一下網(wǎng)站的cookie信息。也可以嘗試清除瀏覽器的cookie洁桌,然后再刷新你登錄的網(wǎng)站渴丸,看是否需要重新登錄。

我這個(gè)項(xiàng)目中用到的express-session就是通過cookie來識(shí)別用戶身份的另凌。使用express-session的好處就是你不需要自己要操作cookie谱轨,使用起來簡單。

后記

我一般寫文章都是針對自己實(shí)際遇到的問題來的途茫,我目前也是在不斷的學(xué)習(xí)中碟嘴,過幾天就會(huì)寫一篇文章作個(gè)總結(jié)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末囊卜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子错沃,更是在濱河造成了極大的恐慌栅组,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件枢析,死亡現(xiàn)場離奇詭異玉掸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)醒叁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門司浪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人把沼,你說我怎么就攤上這事啊易。” “怎么了饮睬?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵租谈,是天一觀的道長。 經(jīng)常有香客問我捆愁,道長割去,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任昼丑,我火速辦了婚禮呻逆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘菩帝。我一直安慰自己咖城,他們只是感情好茬腿,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著酒繁,像睡著了一般滓彰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上州袒,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天揭绑,我揣著相機(jī)與錄音,去河邊找鬼郎哭。 笑死他匪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的夸研。 我是一名探鬼主播邦蜜,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼亥至!你這毒婦竟也來了悼沈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對情侶失蹤姐扮,失蹤者是張志新(化名)和其女友劉穎絮供,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體茶敏,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡壤靶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惊搏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贮乳。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖恬惯,靈堂內(nèi)的尸體忽然破棺而出向拆,到底是詐尸還是另有隱情,我是刑警寧澤宿崭,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布亲铡,位于F島的核電站,受9級(jí)特大地震影響葡兑,放射性物質(zhì)發(fā)生泄漏奖蔓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一讹堤、第九天 我趴在偏房一處隱蔽的房頂上張望吆鹤。 院中可真熱鬧,春花似錦洲守、人聲如沸疑务。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽知允。三九已至撒蟀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間温鸽,已是汗流浹背保屯。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留涤垫,地道東北人姑尺。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像蝠猬,于是被迫代替她去往敵國和親切蟋。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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

  • HTTP cookie(也稱為web cookie,網(wǎng)絡(luò)cookie,瀏覽器cookie或者簡稱cookie)是網(wǎng)...
    留七七閱讀 17,832評(píng)論 2 71
  • 作者:晚晴幽草軒www.jeffjade.com/2016/10/31/115-summary-of-cookie...
    饑人谷_Dylan閱讀 1,222評(píng)論 0 51
  • 背景在HTTP協(xié)議的定義中榆芦,采用了一種機(jī)制來記錄客戶端和服務(wù)器端交互的信息柄粹,這種機(jī)制被稱為cookie,cooki...
    時(shí)芥藍(lán)閱讀 2,355評(píng)論 1 17
  • 注:本文轉(zhuǎn)載自前端大全 背景 在HTTP協(xié)議的定義中匆绣,采用了一種機(jī)制來記錄客戶端和服務(wù)器端交互的信息镰惦,這種機(jī)制被稱...
    楠小忎閱讀 668評(píng)論 0 0
  • cookie cookie的起源 早期web剛開始出現(xiàn)復(fù)雜的應(yīng)用程序時(shí),產(chǎn)生了對于能夠直接在客戶端上存儲(chǔ)用戶信息能...
    zenggo閱讀 3,812評(píng)論 1 52