【问题标题】:How Do You Fix SocketIO Session Data Missing In Express Route Handler?如何修复 Express Route 处理程序中丢失的 SocketIO 会话数据?
【发布时间】:2021-04-20 07:13:35
【问题描述】:

我正在尝试在 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 Handler 控制台输出

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

我在整个互联网上搜索过,但我似乎无法弄清楚。 socketIO 文档也没有帮助。 我还在 stackoverflow 上尝试了其他解决方案,但似乎都没有。

  1. How to share sessions with Socket.IO 1.x and Express 4.x?
  2. express-session isn't setting session cookie while using with socket.io
  3. 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}`);
});

【问题讨论】:

  • 你看过socket.io/docs/v3/middlewares这里的文档吗,讨论wrap函数
  • 使用提供的链接中“与 Express 中间件的兼容性”部分的示例修改了代码。结果是一样的。如果您启动 node.js 服务器并复制我的代码然后尝试一下,您会发现它不是!工作。
  • 您是否看到与此处提供的完整护照示例相同的结果github.com/socketio/socket.io/blob/master/examples/…
  • @TommyBs 我没试过。由于我不打算进行任何身份验证,我认为我不需要 passport.js?
  • 当时我无法尝试任何事情,这就是为什么我认为(希望)一个可行的示例可能是一个很好的起点。我会看看我是否可以使用示例

标签: javascript node.js express session socket.io


【解决方案1】:

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

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

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

【讨论】:

  • 我将安全选项设置为 false。清除 cookie 并再次运行。结果仍然存在。我什至在 Chrome 中以隐身模式运行。甚至尝试过Firefox。结果是一样的。 “快递”:“^4.17.1”“socket.io”:“^3.0.5”
  • 有趣的是这对我有用,尽管我在与后端相同的服务器上运行前端。您可以尝试注销会话 ID 'req.session.id' 并查看它是否在每个请求上都发生变化?这可能与COR有关。设置 cookie 时,您的前端应用是否也使用“secure:true”?
  • 经过调查,我意识到 req.session 没有数据,而是在 req.sessionStore.sessions 中。很奇怪
  • 更新:当您在与后端相同的服务器上运行前端时,我可以确认它可以工作。但是当服务器不同时,req.session 中缺少会话数据,而是在 req.sessionStore.sessions
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-18
  • 1970-01-01
  • 2015-12-07
  • 1970-01-01
  • 1970-01-01
  • 2015-04-30
相关资源
最近更新 更多