在实际项目中有这样一种需求:app允许同【访问 www.tangshuang.net 获取更多精彩内容】未经授权,禁止复制转载。一个用户多点登陆,登陆后用户可能进行某些【版权所有】唐霜 www.tangshuang.net【关注微信公众号:wwwtangshuangnet】操作,这些操作可能影响数据库,同时理论上本文作者:唐霜,转载请注明出处。【关注微信公众号:wwwtangshuangnet】讲会影响界面,而如果是多点登陆,按传统的【版权所有】唐霜 www.tangshuang.net本文作者:唐霜,转载请注明出处。架构,如果用户A进行来某些操作,改变来数【版权所有,侵权必究】【本文受版权保护】据库数据,用户B的用户界面是不会有任何变【原创内容,转载请注明出处】本文版权归作者所有,未经授权不得转载。化,用户B会继续操作并提交数据,这时可能【作者:唐霜】【关注微信公众号:wwwtangshuangnet】提交上来的数据是A改过之前对,导致A的修原创内容,盗版必究。【原创不易,请尊重版权】改反而被B提交的老数据覆盖了。
未经授权,禁止复制转载。【原创内容,转载请注明出处】【原创不易,请尊重版权】友好的操作是,当A对数据库进行提交,并影本文版权归作者所有,未经授权不得转载。本文版权归作者所有,未经授权不得转载。响到B时,应该通知B,让B选择是否采用新转载请注明出处:www.tangshuang.net【版权所有,侵权必究】数据。这种友好的提示被广泛使用。那么在我【未经授权禁止转载】原创内容,盗版必究。们的express应用中如何实现呢?这篇【本文首发于唐霜的博客】【访问 www.tangshuang.net 获取更多精彩内容】文章就利用express和socket.【访问 www.tangshuang.net 获取更多精彩内容】【访问 www.tangshuang.net 获取更多精彩内容】io搭配,实现一套这个需求的逻辑。
著作权归作者所有,禁止商业用途转载。【作者:唐霜】【关注微信公众号:wwwtangshuangnet】【转载请注明来源】著作权归作者所有,禁止商业用途转载。在express应用中加入socket.未经授权,禁止复制转载。【版权所有】唐霜 www.tangshuang.netio
【版权所有】唐霜 www.tangshuang.net未经授权,禁止复制转载。【本文受版权保护】本文作者:唐霜,转载请注明出处。转载请注明出处:www.tangshuang.net大多数前端er都知道socket.io,【本文首发于唐霜的博客】著作权归作者所有,禁止商业用途转载。它是一个基于websocket的库,你可著作权归作者所有,禁止商业用途转载。【版权所有,侵权必究】以用它来方便的实现一些socket需求。未经授权,禁止复制转载。【原创不易,请尊重版权】对于不支持websocket的浏览器,它本文版权归作者所有,未经授权不得转载。【转载请注明来源】也支持降级到ajax轮询来解决。
未经授权,禁止复制转载。【转载请注明来源】本文版权归作者所有,未经授权不得转载。本文版权归作者所有,未经授权不得转载。对于一个应用而言,socket的实现有服原创内容,盗版必究。【原创不易,请尊重版权】务端和客户端两个部分,因此socket.本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.netio有两个package,socket.io这个包是用在node端做server使用本文作者:唐霜,转载请注明出处。原创内容,盗版必究。的,而socket.io-client这个包是在前端做client使用。所以在著作权归作者所有,禁止商业用途转载。【转载请注明来源】你的应用中需要同时安装这两个包,一个用在【未经授权禁止转载】【本文受版权保护】server代码里,一个用在client本文版权归作者所有,未经授权不得转载。【版权所有】唐霜 www.tangshuang.net代码里。
server端的代码未经授权,禁止复制转载。
【原创内容,转载请注明出处】本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。【关注微信公众号:wwwtangshuangnet】【原创不易,请尊重版权】我们server端的应用是express本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。搭建起来的,但是socket.io需要使转载请注明出处:www.tangshuang.net本文版权归作者所有,未经授权不得转载。用http模块创建的纯server,因此未经授权,禁止复制转载。本文版权归作者所有,未经授权不得转载。我们将express创建的app传给ht著作权归作者所有,禁止商业用途转载。转载请注明出处:www.tangshuang.nettp.Server来获得一个纯serve【版权所有】唐霜 www.tangshuang.net本文版权归作者所有,未经授权不得转载。r:
【转载请注明来源】本文作者:唐霜,转载请注明出处。【本文首发于唐霜的博客】【转载请注明来源】转载请注明出处:www.tangshuang.netimport express from "express";
import http from "http";
import socketIoServer from "socket.io";
const app = express();
const server = http.Server(app);
const io = new socketIoServer(server);
io.on("connection", (socket) => { ... });
server.listen(3000);
这是一个大致的框架,中间省略来app的各本文作者:唐霜,转载请注明出处。【访问 www.tangshuang.net 获取更多精彩内容】种路由,以及io的connection里【本文受版权保护】【作者:唐霜】面的内容。这段代码告诉我们如何让expr【版权所有】唐霜 www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】ess的应用启动时,同时启动socket转载请注明出处:www.tangshuang.net著作权归作者所有,禁止商业用途转载。.io创建的服务。
【本文首发于唐霜的博客】【版权所有,侵权必究】著作权归作者所有,禁止商业用途转载。client端的代码【访问 www.tangshuang.net 获取更多精彩内容】
【本文受版权保护】【版权所有】唐霜 www.tangshuang.net未经授权,禁止复制转载。【未经授权禁止转载】客户端的socket.io在api上和服【关注微信公众号:wwwtangshuangnet】【版权所有,侵权必究】务端的非常像,只不过由于宿主环境不同,所未经授权,禁止复制转载。【原创内容,转载请注明出处】以要在内部实现上采用不同的方式,因此分来【版权所有】唐霜 www.tangshuang.net转载请注明出处:www.tangshuang.net两个包来做。而且如果了解网络握手的相关知【版权所有,侵权必究】本文版权归作者所有,未经授权不得转载。识,大致可以知道建立socket连接都要著作权归作者所有,禁止商业用途转载。本文作者:唐霜,转载请注明出处。走哪些网络连接的步骤。我们来看下clie【作者:唐霜】【未经授权禁止转载】nt端代码:
【转载请注明来源】【原创不易,请尊重版权】【未经授权禁止转载】import socketIoClient from 'socket.io-client';
let io = new socketIoClient();
io.on("connection", (socket) => { ... });
可以看到,基本没啥差别。在我们没有深入之【版权所有】唐霜 www.tangshuang.net原创内容,盗版必究。前,可以把一个客户端于服务端的一个连接当本文版权归作者所有,未经授权不得转载。【原创内容,转载请注明出处】作点对点(P2P),由客户端率先发起so本文作者:唐霜,转载请注明出处。【作者:唐霜】cket连接,连接成功之后客户端和服务端【版权所有】唐霜 www.tangshuang.net【本文首发于唐霜的博客】的connection事件被触发,两端的本文版权归作者所有,未经授权不得转载。【关注微信公众号:wwwtangshuangnet】所有操作都在这个事件的回调函数中执行,双本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。方都可以通过发起.disconnect(【作者:唐霜】原创内容,盗版必究。)来断开连接。
转载请注明出处:www.tangshuang.net原创内容,盗版必究。【本文首发于唐霜的博客】【关注微信公众号:wwwtangshuangnet】cookie方式确定用户身份转载请注明出处:www.tangshuang.net
【本文受版权保护】转载请注明出处:www.tangshuang.net【作者:唐霜】原创内容,盗版必究。【关注微信公众号:wwwtangshuangnet】我们大部分应用通过cookie来确定某个【本文首发于唐霜的博客】【原创不易,请尊重版权】用户的身份,对于多点登陆用户而言,虽然是著作权归作者所有,禁止商业用途转载。【原创内容,转载请注明出处】同一个用户,但cookie是不同的,因此著作权归作者所有,禁止商业用途转载。原创内容,盗版必究。,我们要通过cookie找出user i本文作者:唐霜,转载请注明出处。【访问 www.tangshuang.net 获取更多精彩内容】d来确定身份。在服务端,要通过user 未经授权,禁止复制转载。【作者:唐霜】id来决定socket的一条消息要发送给原创内容,盗版必究。本文作者:唐霜,转载请注明出处。哪个客户端。那么怎么确定身份呢?
本文版权归作者所有,未经授权不得转载。著作权归作者所有,禁止商业用途转载。【原创内容,转载请注明出处】本文作者:唐霜,转载请注明出处。socket.io新版本已经官方支持co未经授权,禁止复制转载。著作权归作者所有,禁止商业用途转载。okie获取了,cookie被保存在socket.handshake.headers.cookie中,然而这里得到的cookie是一个完整著作权归作者所有,禁止商业用途转载。【关注微信公众号:wwwtangshuangnet】的原始cookie,我们希望通过一个pa【原创不易,请尊重版权】本文作者:唐霜,转载请注明出处。rser工具把它解析成对象的形式便于我们本文版权归作者所有,未经授权不得转载。【关注微信公众号:wwwtangshuangnet】获取。cookie-parser这个包已原创内容,盗版必究。本文版权归作者所有,未经授权不得转载。经做了这件事,express应用直接用它【原创内容,转载请注明出处】未经授权,禁止复制转载。来解析,而一个叫socket.io-co本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。okie-parser的包对它进行来封装【版权所有,侵权必究】【版权所有,侵权必究】,让socket.io也支持同样的方式:
import express from "express";
import cookieParser from "cookie-parser";
import socketIoServer from "socket.io";
import socketIoCookieParser from "socket.io-cookie-parser";
import http from "http";
const app = express();
const server = http.Server(app);
const io = new socketIoServer(server);
app.use(cookieParser());
io.use(socketIoCookieParser());
io.on("connection", (socket) => {
let cookies = socket.request.cookies;
let autcookie = cookies.auth;
// 接下来通过你系统内部的机制,通过这个cookie去获取用户的user id
...
});
server.listen(3000);
上面这段代码演示了怎么在socket.i【原创不易,请尊重版权】【关注微信公众号:wwwtangshuangnet】o中获取cookie信息,而你的expr【原创内容,转载请注明出处】【原创不易,请尊重版权】ess中也可以获取一模一样的cookie【本文受版权保护】【未经授权禁止转载】,所以就有了对应关系。
【版权所有】唐霜 www.tangshuang.net转载请注明出处:www.tangshuang.net【版权所有,侵权必究】【原创不易,请尊重版权】转载请注明出处:www.tangshuang.nethttp保存,socket推送【关注微信公众号:wwwtangshuangnet】
转载请注明出处:www.tangshuang.net【本文受版权保护】【本文受版权保护】本文版权归作者所有,未经授权不得转载。【本文受版权保护】现在进入最关键的一个环节。前面的两节帮我转载请注明出处:www.tangshuang.net【原创不易,请尊重版权】们解决了express和socket.i【访问 www.tangshuang.net 获取更多精彩内容】【版权所有】唐霜 www.tangshuang.neto的部署问题,但是怎么融合还没有讲。让我【原创不易,请尊重版权】【版权所有】唐霜 www.tangshuang.net们回到一个现实的案例中,我们创建了一个聊未经授权,禁止复制转载。本文版权归作者所有,未经授权不得转载。天室,一个用户发送消息到服务端,我们采用【本文受版权保护】转载请注明出处:www.tangshuang.netajax请求发送(虽然实际上可以采用so【关注微信公众号:wwwtangshuangnet】本文作者:唐霜,转载请注明出处。cket.io的客户端程序发送),他自己【转载请注明来源】转载请注明出处:www.tangshuang.net本地可以马上显示这条消息,问题是,其它用【访问 www.tangshuang.net 获取更多精彩内容】【版权所有】唐霜 www.tangshuang.net户的屏幕上怎么马上显示这条消息呢?我们需【作者:唐霜】【原创内容,转载请注明出处】要通过服务端发出一个消息推送,把更新的内【作者:唐霜】【关注微信公众号:wwwtangshuangnet】容推送给所有客户端,这样所有客户端就可以原创内容,盗版必究。转载请注明出处:www.tangshuang.net得到新的内容并显示在界面上。
【访问 www.tangshuang.net 获取更多精彩内容】【转载请注明来源】原创内容,盗版必究。原创内容,盗版必究。【关注微信公众号:wwwtangshuangnet】逻辑看上去很简单。而且如果你对socke【未经授权禁止转载】【转载请注明来源】t.io有了解的话,通过服务端一个soc原创内容,盗版必究。【版权所有】唐霜 www.tangshuang.netket.broadcast.emit和客【关注微信公众号:wwwtangshuangnet】【版权所有,侵权必究】户端的socket.on,可以很容易实现【关注微信公众号:wwwtangshuangnet】【版权所有,侵权必究】。问题在于怎么把“http保存消息完再s【本文首发于唐霜的博客】【未经授权禁止转载】ocket推送”这个逻辑实现。
本文作者:唐霜,转载请注明出处。【作者:唐霜】【本文首发于唐霜的博客】【本文受版权保护】我们的大部分api都是restful的,本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net因此保存这个消息常常是一个post请求,转载请注明出处:www.tangshuang.net【版权所有,侵权必究】得到这个请求之后,我们在express的转载请注明出处:www.tangshuang.net【转载请注明来源】某个路由中实现写入数据库的过程。然而我们【本文受版权保护】【访问 www.tangshuang.net 获取更多精彩内容】去研究socket.io的使用方式,发现未经授权,禁止复制转载。【原创内容,转载请注明出处】socket.io的响应是独立的作用域,【转载请注明来源】转载请注明出处:www.tangshuang.net和express创建的app是分离的。
【作者:唐霜】著作权归作者所有,禁止商业用途转载。
因此,我们要提供一个全局的变量来保存每【访问 www.tangshuang.net 获取更多精彩内容】【原创内容,转载请注明出处】一个socket连接,并且把每一个soc【作者:唐霜】【本文受版权保护】ket连接和建立它的用户对应起来。
import express from "express"; import cookieParser from "cookie-parser"; import socketIoServer from "socket.io"; import socketIoCookieParser from "socket.io-cookie-parser"; import http from "http"; const app = express(); const server = http.Server(app); const io = new socketIoServer(server); const sockets = {}; app.use(cookieParser()); io.use(socketIoCookieParser()); app.use((req, res, next) => { app.sockets = req.sockets = res.sockets = sockets; next(); }); io.on("connection", (socket) => { let cookies = socket.request.cookies; let autcookie = cookies.auth; if (!autcookie) { console.log("a user connected by socket, but without sso cookie, so disconnected."); socket.disconnect(); return; } getUserId(autcookie).then((uid) => { sockets[uid] = sockets[uid] || []; sockets[uid].push(socket); io.on("disconnection", () => { sockets[uid] = sockets[uid].filter((item) => item !== socket); }); }); }); server.listen(3000);
这其实是一个比较hack的手法,但是可以转载请注明出处:www.tangshuang.net【原创不易,请尊重版权】解决我们的问题。我们创建来一个全局的so【原创内容,转载请注明出处】【关注微信公众号:wwwtangshuangnet】ckets变量,并把这个变量赋值给exp【版权所有,侵权必究】著作权归作者所有,禁止商业用途转载。ress创建的app,这样我们就可以在路【作者:唐霜】未经授权,禁止复制转载。由里面使用sockets这个属性了。
原创内容,盗版必究。【原创内容,转载请注明出处】【转载请注明来源】未经授权,禁止复制转载。这个sockets保存了所有的socke未经授权,禁止复制转载。【转载请注明来源】t连接,并且第一层按照userid进行保【作者:唐霜】本文作者:唐霜,转载请注明出处。存,也就是说在路由里面只要知道useri原创内容,盗版必究。本文作者:唐霜,转载请注明出处。d,就可以知道这个用户都建立了哪些soc本文作者:唐霜,转载请注明出处。【未经授权禁止转载】ket。第二层是一个数组,因为相同use转载请注明出处:www.tangshuang.net原创内容,盗版必究。rid的登陆用户可能在多个地方登陆了,因本文作者:唐霜,转载请注明出处。【本文受版权保护】此可能建立多个socket连接,我们还要【本文受版权保护】【未经授权禁止转载】用这个数组实现推送,即当其中一个客户端更转载请注明出处:www.tangshuang.net【原创内容,转载请注明出处】新了,我们先找出userid,然后得到这本文版权归作者所有,未经授权不得转载。【版权所有,侵权必究】个数组,并且遍历这个数组,对每一个soc著作权归作者所有,禁止商业用途转载。【未经授权禁止转载】ket抛出一个推送消息,这样,虽然是同一【本文受版权保护】本文作者:唐霜,转载请注明出处。个userid但不同client就可以接【关注微信公众号:wwwtangshuangnet】【版权所有,侵权必究】收到更新提示。
【版权所有】唐霜 www.tangshuang.net著作权归作者所有,禁止商业用途转载。【转载请注明来源】getUserId是我自己的内部函数,不【本文受版权保护】本文版权归作者所有,未经授权不得转载。需要公开。不过,在disconnect的未经授权,禁止复制转载。【关注微信公众号:wwwtangshuangnet】时候,我们不忘把这个socket从soc转载请注明出处:www.tangshuang.net转载请注明出处:www.tangshuang.netkets中删除,这是一个好习惯,也保证程【关注微信公众号:wwwtangshuangnet】【版权所有】唐霜 www.tangshuang.net序不会出错。
【原创不易,请尊重版权】【版权所有】唐霜 www.tangshuang.net本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。小结原创内容,盗版必究。
【原创不易,请尊重版权】未经授权,禁止复制转载。原创内容,盗版必究。上面的阐述主要还是从server端去阐述未经授权,禁止复制转载。本文作者:唐霜,转载请注明出处。,没有考虑客户端提示应该怎么做。其实客户著作权归作者所有,禁止商业用途转载。转载请注明出处:www.tangshuang.net端也是在某个on中进行提示处理,或者你可未经授权,禁止复制转载。转载请注明出处:www.tangshuang.net以更自动一些,得到这个推送之后,自己默认【访问 www.tangshuang.net 获取更多精彩内容】未经授权,禁止复制转载。发一个新的ajax去获取最新数据。通过本本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。文,主要让你可以了解如何实现http和s转载请注明出处:www.tangshuang.net著作权归作者所有,禁止商业用途转载。ocket的结合。
转载请注明出处:www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】【原创不易,请尊重版权】本文版权归作者所有,未经授权不得转载。著作权归作者所有,禁止商业用途转载。2018-03-05 7080 socket


