從前端到后臺:一個聊天項目帶你擼全棧

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

項目概述

該聊天App高仿iOS端的微信,當然沒這么復雜,目前已實現(xiàn)功能有:

  • 用戶注冊、登錄、注銷功能;
  • 自動緩存已登錄用戶,關閉瀏覽器窗口失效;
  • 聊天室:所以在線用戶之間聊天;
  • 與在線用戶之間聊天;
  • 獲取所有在線用戶;
  • 獲取好友列表;
  • 添加好友:后臺接口已完成,前端目前尚未實現(xiàn)。

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

前端Web界面

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

對前端我就不做深入的介紹了,主要是基于Vue來實現(xiàn)的。而且對于一個前端開發(fā)者來說,后臺實現(xiàn)可能更具有挑戰(zhàn)性。

后臺實現(xiàn)

為了實現(xiàn)真實的聊天功能,我決定自己來搭建后臺,這也是我第一次寫后臺。整個后臺應用基于Node.js平臺,采用express模塊來搭建HTTP服務器,聊天功能采用WebSocket實現(xiàn),數(shù)據(jù)庫使用的是MongoDB。

主要使用的技術棧包括:Node.jsexpress、express-session、express-wsmongodb、mongoose。

后臺邏輯分析

初次寫后臺,最難的可能就是架構了,因為你要對整個應用的需求、實現(xiàn)的功能、數(shù)據(jù)的模型等有一個清晰的思路邏輯。我可能也就是在這方面花的時間是最多的,總是不知道該如何下手。很多次都是寫著寫著就寫不下去了,因為邏輯行不通了。

遇到的問題和難點

  • 如何判斷用戶是否是登錄狀態(tài)?如何記住用戶的登錄狀態(tài)?
  • 如何斷定當前登錄的用戶是否成功連接了WebSocket服務器?
  • 當一個來自客戶端的websocket請求時,如何判斷該用戶是否已登錄?需要一個身份識別功能,否則誰都可以任意接入websockt服務器了。
  • HTTP服務器與WebSocket服務器之間如何并存?又如何交互?因為只有聊天功能和消息推送功能使用ws,其他所有的請求都是與http服務器通信。
  • ws服務器如何判斷消息的轉發(fā)目標?如果目標用戶不在線又如何處理?
  • 如何搭建數(shù)據(jù)庫?對于初次接觸的人來說這也是個難題。
  • 如何連接和操作數(shù)據(jù)庫?起碼要基本的增刪改查。
  • 密碼加密問題,這同樣是一個很大的難題。

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

其實,學習也就是一個發(fā)現(xiàn)問題,然后解決問題的過程。當你把一個一個的問題都解決之后,你也就在不知不覺中慢慢成長起來了。貴在堅持,也難在堅持。

模塊介紹

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

  • express:基本上是整個后臺應用的支撐,HTTP和ws都是建立在此基礎之上。一個Node.js上很強大的東西,可以讓你快速創(chuàng)建一個Web應用。
  • express-session:這個是express的插件,主要用來解決上面說到的判斷用戶是否登錄的問題。
  • express-ws:這也是一個express的插件,用來構件一個ws服務器。之前采用的是ws框架,但與express交互性太差,不好在wshttp之間通信。
  • body-parser:一個express框架,主要用來解析POST請求發(fā)過來的數(shù)據(jù)。
  • mongoose:一個用來操作mongodb數(shù)據(jù)庫的框架。還有一個叫做mongolass的框架,比這個量級要輕。

主目錄結構

由于是第一次寫后臺,后臺結構分的并不是很清晰。

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

主要的架構就是這樣,基本操作都在routes目錄下,因為后臺也就是為前端寫接口。在routes目錄下又分了不同的子路由,比如:friend、userws、message等,分別處理不同的請求。

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

兩個容易誤會的概念

本篇文章主要作個整體的介紹,因為該Web應用目前仍在開發(fā)中,很多功能還不確定,等后面整個邏輯清晰了再作總結。下面說兩個很經(jīng)典的問題,也是前端很容易誤會的問題,至少我是誤會了很久。

跨域

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

在這之前,對跨域訪問是一知半解,不知道到底該如何解決這個問題。這里要提出,跨域訪問不是前端的問題,其實大部分都是后臺的問題。對于跨域,網(wǎng)上有兩種解決方案:JSONP和Ajax。對于JSONP沒什么研究,不作介紹,好像也并不是很實用,這里主要介紹Ajax跨域的問題。

下面是我后臺解決跨域問題的方案:

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();
});

簡單的說一下,跨域其實瀏覽器是可以正常的收到來自于服務的響應,只是無法正確的解析。通過在服務器端對響應頭寫入'Access-Control-Allow-Origin': '*''Access-Control-Allow-Methods': 'GET,POST',瀏覽器才能正確的解析服務器的響應。記住是在服務器端對響應頭的操作,我之前一直誤會是在前端的請求頭中寫入,現(xiàn)在想想有點傻逼了。

對于'Access-Control-Allow-Credentials': true,是用來處理跨域中cookie的問題。因為默認情況下,cookie是不允許在跨域訪問中傳輸?shù)摹R鉀Q這個問題,Access-Control-Allow-Origin的值就不能為通配符*,并且前端通過Ajax發(fā)起請求時也要做處理。

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

Cookie

之前對Cookie的認識一直就是一種類似于緩存的東西,但具體是做什么,怎么用,并不清楚。這是要指出兩點:

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

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

因為cookie是每次發(fā)起請求都會自動攜帶的,所以服務器就可以通過cookie來識別用戶的身份、是否處于登錄狀態(tài)等,就像你進入某個網(wǎng)站有時候會自動識別你的身份并登錄。而cookie也是可以設置過期時間的,所以服務器端就可以控制你的身份多久失效,失效之后你就要重新登錄了。

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

我這個項目中用到的express-session就是通過cookie來識別用戶身份的。使用express-session的好處就是你不需要自己要操作cookie,使用起來簡單。

后記

我一般寫文章都是針對自己實際遇到的問題來的,我目前也是在不斷的學習中,過幾天就會寫一篇文章作個總結。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • HTTP cookie(也稱為web cookie,網(wǎng)絡cookie,瀏覽器cookie或者簡稱cookie)是網(wǎng)...
    留七七閱讀 18,382評論 2 71
  • 作者:晚晴幽草軒www.jeffjade.com/2016/10/31/115-summary-of-cookie...
    饑人谷_Dylan閱讀 1,262評論 0 51
  • 背景在HTTP協(xié)議的定義中,采用了一種機制來記錄客戶端和服務器端交互的信息,這種機制被稱為cookie,cooki...
    時芥藍閱讀 2,470評論 1 17
  • 注:本文轉載自前端大全 背景 在HTTP協(xié)議的定義中,采用了一種機制來記錄客戶端和服務器端交互的信息,這種機制被稱...
    楠小忎閱讀 740評論 0 0
  • cookie cookie的起源 早期web剛開始出現(xiàn)復雜的應用程序時,產(chǎn)生了對于能夠直接在客戶端上存儲用戶信息能...
    zenggo閱讀 4,008評論 1 52

友情鏈接更多精彩內(nèi)容