如何修复 Express Route 处理程序中丢失的 SocketIO 会话数据?

How Do You Fix SocketIO Session Data Missing In Express Route Handler?

我正在尝试在 nodejs 服务器上的 Express 和 SocketIO 之间共享会话数据。我在网上研究了如何在 https://socket.io/docs/v3/faq/#Usage-with-express-session

上实现它

注意:底部的前端和后端代码

任何时候我访问主页 http://localhost:5000 套接字连接成功并且会话包含 myData socketio初始连接中设置的值

SocketIO 控制台输出

Session {
  cookie: {
    path: '/',
    _expires: null,
    originalMaxAge: null,
    httpOnly: true,
    secure: true
  },
  myData: 'hello world'
}

然而,当一个请求发送到 http://localhost:5000/api/download 时控制台输出在Express 处理程序不包含会话中的 myData 值。 这表明即使 socketIO 正在保存会话数据,它也不会与 Express 共享。

Express 处理程序控制台输出

Session {
  cookie: {
    path: '/',
    _expires: null,
    originalMaxAge: null,
    httpOnly: true,
    secure: true
  }
}

我在网上找遍了,好像也想不通。 socketIO 文档也没有帮助。 我还在 Whosebug 上尝试了其他解决方案,但 none 似乎有效。

  1. How to share sessions with Socket.IO 1.x and Express 4.x?
  2. socket.io and session?

这个问题是我最后一次寻求帮助解决问题的尝试。

谢谢

我的代码为前端和后端设置

前端 HTML: (index.html)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1"
      crossorigin="anonymous"
    />
    <title>File Download Progress</title>
  </head>
  <body class="vh-100 w-2">
    <div class="d-flex flex-column align-items-center vh-100">
      <div>
        <div class="d-flex flex-column align-items-center mt-5">
          <h1 class="m-5">File Download Progress</h1>

          <button class="m-1 w-100 btn btn-success" id="dl-btn">
            Download
          </button>
        </div>
      </div>
    </div>

    <script
      src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js"
      integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW"
      crossorigin="anonymous"
    ></script>
    <script src="./socket.io.min.js"></script>
    <script src="./app.js"></script>
  </body>
</html>

前端:(app.js)

const downloadBtn = document.getElementById("dl-btn");
const socket = io("http://localhost:5000");

socket.on("connected", () => {
  console.log("server connected");
});

downloadBtn.addEventListener("click", () => {
  window.location = "http://localhost:5000/api/download";
});

后端:

import express from "express";
import session from "express-session";
import { createServer } from "http";
import { Server } from "socket.io";
import cors from "cors";
import bodyParser from "body-parser";
import asyncHandler from "express-async-handler";

const app = express();
const server = createServer(app);

const io = new Server(server, {
  cors: {
    origin: "http://localhost:3000",
    methods: ["GET", "POST"],
  },
});

const port = 5000;

const corsOptions = {
  origin: "http://localhost:3000",
  optionsSuccessStatus: 200,
};

const sessionMiddleware = session({
  secret: "keyboard cat",
  resave: false,
  saveUninitialized: true,
  cookie: { secure: true },
});

app.use(cors(corsOptions));
app.use(bodyParser.urlencoded({ extended: true }));

app.use(sessionMiddleware);
io.use((socket, next) => {
  sessionMiddleware(socket.request, socket.request.res || {}, next);
});

app.get("/api/", (req, res) => {
  res.send("API is running");
});

app.get(
  "/api/download",
  asyncHandler(async (req, res) => {
    console.log(req.session);
    res.send("hello");
  })
);

io.on("connection", (socket) => {
  socket.emit("connected");
  console.log("client connected");
  const session = socket.request.session;
  session.myData = "hello world";
  session.save();

  console.log(session);
});

server.listen(port, () => {
  console.log(`listening at http://localhost:${port}`);
});

经过大量调查,我相信我已经找到了问题所在(而且比我想象的要简单得多)。

我注意到每个请求(websocket 和 http)都会生成一个新的会话 ID。我认为这个问题的原因是因为您为您的 cookie 设置了 secure:true,但我相信您是 运行 通过 http 而不是 https。

清除所有 cookie,将安全选项设置为 false(对于生产环境,您很可能希望它为 true)并再次 运行 您的应用程序,看看是否获得了预期的结果。