从前端到后台(一个聊天项目带你撸全栈)
差不多花了整整两个星期,终于把这个聊天APP的后台架构搭建出来了。虽然花的时间比较多,但这也是我第一次写后台,其实也并没有想象中的那么难,但也还是很折腾,尤其是在数据库这一块,几乎全部都是英文文档(看得都只想**)。
项目概述
该聊天App高仿iOS端的微信,当然没这么复杂,目前已实现功能有:
- 用户注册、登录、注销功能;
- 自动缓存已登录用户,关闭浏览器窗口失效;
- 聊天室:所以在线用户之间聊天;
- 与在线用户之间聊天;
- 获取所有在线用户;
- 获取好友列表;
- 添加好友:后台接口已完成,前端目前尚未实现。
前端Web界面
前端界面在一个多月前就已经差不多写出来了,苦于一直没有后台接口(API)的支持,所以仅仅只是一个界面展示,并无实际聊天的功能。
- github地址:https://github.com/moohng/wchat-vue
- 在线测试地址:http://mohng.com/wchat-vue
Vue
来实现的。而且对于一个前端开发者来说,后台实现可能更具有挑战性。后台实现
为了实现真实的聊天功能,我决定自己来搭建后台,这也是我第一次写后台。整个后台应用基于
Node.js
平台,采用express
模块来搭建HTTP服务器,聊天功能采用WebSocket
实现,数据库使用的是MongoDB
。- github地址:https://github.com/moohng/wchat-sv
Node.js
、express
、express-session
、express-ws
、mongodb
、mongoose
。后台逻辑分析 初次写后台,最难的可能就是架构了,因为你要对整个应用的需求、实现的功能、数据的模型等有一个清晰的思路逻辑。我可能也就是在这方面花的时间是最多的,总是不知道该如何下手。很多次都是写着写着就写不下去了,因为逻辑行不通了。
遇到的问题和难点
- 如何判断用户是否是登录状态?如何记住用户的登录状态?
- 如何断定当前登录的用户是否成功连接了
WebSocket
服务器? - 当一个来自客户端的
websocket
请求时,如何判断该用户是否已登录?需要一个身份识别功能,否则谁都可以任意接入websockt
服务器了。 - HTTP服务器与
WebSocket
服务器之间如何并存?又如何交互?因为只有聊天功能和消息推送功能使用ws
,其他所有的请求都是与http服务器通信。 -
ws
服务器如何判断消息的转发目标?如果目标用户不在线又如何处理? - 如何搭建数据库?对于初次接触的人来说这也是个难题。
- 如何连接和操作数据库?起码要基本的增删改查。
- 密码加密问题,这同样是一个很大的难题。
其实,学习也就是一个发现问题,然后解决问题的过程。当你把一个一个的问题都解决之后,你也就在不知不觉中慢慢成长起来了。贵在坚持,也难在坚持。
模块介绍
对于上面的问题,我也是自己网上找资料,目前主要引用到了这些模块框架:
-
express
:基本上是整个后台应用的支撑,HTTP和ws
都是建立在此基础之上。一个Node.js
上很强大的东西,可以让你快速创建一个Web应用。 -
express-session
:这个是express
的插件,主要用来解决上面说到的判断用户是否登录的问题。 -
express-ws
:这也是一个express
的插件,用来构件一个ws
服务器。之前采用的是ws
框架,但与express
交互性太差,不好在ws
和http
之间通信。 -
body-parser
:一个express
框架,主要用来解析POST
请求发过来的数据。 -
mongoose
:一个用来操作mongodb
数据库的框架。还有一个叫做mongolass
的框架,比这个量级要轻。
由于是第一次写后台,后台结构分的并不是很清晰。
-
index.js
:入口文件,创建一个http服务器和一个ws服务器,并连接到数据库。 -
model
:该目录主要写一些与数据库交互的代码。 -
routes
:这个目录主要处理路由,大部分的操作都是在该目录下进行的。
routes
目录下,因为后台也就是为前端写接口。在routes
目录下又分了不同的子路由,比如:friend
、user
、ws
、message
等,分别处理不同的请求。看起来很简单,但做起来真的不容易,最可怕的是代码量大了,你会陷入一个大量重复代码和无限回调的噩梦,我想大部分人都经历过
js
的回调噩梦。目前也只是有了个初步的逻辑架构,后面可能会根据需求的不同而变更。代码也需要优化,有的自己一遍一遍写起来就恶心。两个容易误会的概念 本篇文章主要作个整体的介绍,因为该Web应用目前仍在开发中,很多功能还不确定,等后面整个逻辑清晰了再作总结。下面说两个很经典的问题,也是前端很容易误会的问题,至少我是误会了很久。
跨域
【从前端到后台(一个聊天项目带你撸全栈)】我的前端页面是托管在GitHub上的,通过开启静态页面的功能,可使用域名来访问http://mohng.com/wchat-vue。而我的后台是搭建在自己的服务器中的,所以自然就面临了一个问题:跨域访问。
在这之前,对跨域访问是一知半解,不知道到底该如何解决这个问题。这里要提出,跨域访问不是前端的问题,其实大部分都是后台的问题。对于跨域,网上有两种解决方案: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'
,浏览器才能正确的解析服务器的响应。记住是在服务器端对响应头的操作,我之前一直误会是在前端的请求头中写入,现在想想有点傻逼了。对于
'Access-Control-Allow-Credentials': true
,是用来处理跨域中cookie的问题。因为默认情况下,cookie是不允许在跨域访问中传输的。要解决这个问题,Access-Control-Allow-Origin
的值就不能为通配符*
,并且前端通过Ajax发起请求时也要做处理。$.ajax(url, {
method: 'GET',
xhrFields: {
withCredentials: true
},
...
})
Cookie
之前对
Cookie
的认识一直就是一种类似于缓存的东西,但具体是做什么,怎么用,并不清楚。这是要指出两点:- Cookie基本上都是由后台来管理的,前端不需要任何操作
- Cookie信息会在每次发起的请求中自动携带
Cookie
的。虽然也可以通过js
代码读取到cookie
数据,但大部分服务器都是禁用掉此操作,也就是让你在前端无法通过js
代码读取到cookie
的内容,读取到的是空字符串。因为
cookie
是每次发起请求都会自动携带的,所以服务器就可以通过cookie
来识别用户的身份、是否处于登录状态等,就像你进入某个网站有时候会自动识别你的身份并登录。而cookie
也是可以设置过期时间的,所以服务器端就可以控制你的身份多久失效,失效之后你就要重新登录了。你可以自己尝试在浏览器的控制台通过
document.cookie
来获取一下网站的cookie
信息。也可以尝试清除浏览器的cookie
,然后再刷新你登录的网站,看是否需要重新登录。我这个项目中用到的
express-session
就是通过cookie
来识别用户身份的。使用express-session
的好处就是你不需要自己要操作cookie
,使用起来简单。后记 我一般写文章都是针对自己实际遇到的问题来的,我目前也是在不断的学习中,过几天就会写一篇文章作个总结。
推荐阅读
- 2018-02-06第三天|2018-02-06第三天 不能再了,反思到位就差改变
- 一个小故事,我的思考。
- Docker应用:容器间通信与Mariadb数据库主从复制
- 第三节|第三节 快乐和幸福(12)
- 你到家了吗
- 一个人的碎碎念
- 遇到一哭二闹三打滚的孩子,怎么办┃山伯教育
- 死结。
- 我从来不做坏事
- 赢在人生六项精进二阶Day3复盘