使用nodejs显示网站上当前的唯一用户数

displaying current number of unique users on website using nodejs

我试图在我网站的特定页面上显示当前用户数。我知道 socket.io 是为了做这件事,但互联网上的每个解决方案都有一个单独的 server.js 文件来使其工作。我的问题是,我如何使用 app.js 来实现这个,我已经为我的网站使用配置,侦听端口 3000。抱歉,如果我的问题有点天真,但我最近开始了网络开发并且没有确切地知道如何做到这一点。

我的app.js如下:

//jshint esversion:6

require('dotenv').config();
const express = require('express');
const bodyParser = require('body-parser');
const ejs = require('ejs');
const _ = require('lodash');
const mongoose = require('mongoose');
const session = require('express-session');
const passport = require('passport');
const passportLocalMongoose = require('passport-local-mongoose');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const findOrCreate = require('mongoose-findorcreate');

const app = express();

app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static("public"));

//Passport Sessions setup
app.use(session({
  secret: "Our little secret.",
  resave: false,
  saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());

// Users DB
let conn = mongoose.createConnection("mongodb+srv://@cluster0.wrvir.mongodb.net/userDB", {useNewUrlParser: true, useUnifiedTopology: true});
// conn.set("useCreateIndex", true);

const userSchema = new mongoose.Schema ({
  username: String,
  // password:String,
  googleId: String
});

userSchema.plugin(passportLocalMongoose);
userSchema.plugin(findOrCreate);

const User = conn.model("User", userSchema);

passport.use(User.createStrategy());

passport.serializeUser(function(user, done){
  done(null, user.id);
});

passport.deserializeUser(function(id, done){
  User.findById(id, function(err, user){
    done(err, user);
  });
});

// Google Authentication Strategy
passport.use(new GoogleStrategy({
    clientID: process.env.CLIENT_ID,
    clientSecret: process.env.CLIENT_SECRET,
    callbackURL: "http://localhost:3000/auth/google/timeline",
    userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
  },
  function(accessToken, refreshToken, profile, cb) {
    console.log(profile);
    User.findOrCreate({ googleId: profile.id, username: profile.displayName }, function (err, user) {
      return cb(err, user);
    });
  }
));

// Stories DB
let conn2 = mongoose.createConnection("mongodb+srv://@cluster0.wrvir.mongodb.net/storiesDB", {useNewUrlParser: true, useUnifiedTopology: true});

const postSchema = {
  title: String,
  content: String
};

const Post = conn2.model("Post", postSchema);

app.get("/", function(req, res){
  res.render("home");
});

app.get("/auth/google",
  passport.authenticate("google", { scope: ["profile"] })
);

app.get("/auth/google/timeline",
  passport.authenticate("google", { failureRedirect: '/login' }),
  function(req, res) {
    // Successful authentication, redirect to timeline.
    res.redirect('/timeline');
  });

app.get("/posts/:postid", function(req, res){
  const requestedPostId = req.params.postid;
  Post.findOne({_id: requestedPostId}, function(err, post){
   res.render("post", {
     title: post.title,
     content: post.content
   });
 });
});

app.get("/compose", function(req, res){
  res.render("compose");
});

app.post("/compose", function(req, res){
  const post = new Post({
    title: req.body.postTitle,
    content: req.body.postBody
  });

  post.save(function(err){
   if (!err){
     res.redirect("/timeline");
   }
 });
});

app.get("/timeline", function(req, res){
  if(req.isAuthenticated()){
    Post.find({},function(err, posts){
      res.render("timeline", {
        startingContent: homeStartingContent,
        posts: posts
      });
    });
  } else {
    res.redirect("/login");
  }
});

app.get("/logout", function(req, res){
  req.logout();
  res.redirect("/");
});

app.listen(process.env.PORT || 3000, function(){
  console.log("Server started on port 3000...");
});

服务器端

代码末尾的 `app.listen` 函数 returns 一个 `server` 对象,然后可以使用它来设置这样的套接字:
const socketio = require('socket.io');

// ...

const PORT = process.env.PORT || 3000;
const server = app.listen(PORT, () => console.log(`Server started on port ${PORT}.`));

const io = socketio(server);

然后您可以使用以下逻辑来计算您的用户并在计数发生变化时向每个用户发出事件:

let userCount = 0;

io.on('connection', socket => {
  userCount++;
  io.emit('user-count-change', userCount);

  socket.on('disconnect', () => {
    userCount--;
    io.emit('user-count-change', userCount);
  });
});

可选
但是由于这段代码会不断地向每个连接上的每个用户发出事件,所以发出的次数会呈指数增长。作为解决方案,我会在一个间隔内触发事件,中间有一点延迟:

const userCountUpdateDelay = 10000;

let userCount = 0;

io.on('connection', socket => {
  userCount++;
  socket.on('disconnect', () => { userCount--; });

  socket.emit('user-count-change', userCount);
});

setInterval(() => {
  io.emit('user-count-change', userCount);
}, userCountUpdateDelay);

客户端

将此 html 添加到您网站的某处:
<script src="/socket.io/socket.io.js"></script>
<script>
  const socket = io();

  socket.on('user-count-change', function (userCount) {
    console.log(userCount);
    // Display the user count...
  });
</script>

了解更多

如果您想了解有关 socket.io 的更多信息,它有一个很棒的文档,您可以找到 here