Node.js 在real-time tweet streamer socket.io应用程序上将标题发送到客户端后,无法设置标题

Node.js 在real-time tweet streamer socket.io应用程序上将标题发送到客户端后,无法设置标题,node.js,twitter,Node.js,Twitter,我正在node.js和react.js上创建一个实时twitter拖缆应用程序,在npm启动时遇到了这个错误。我已经修复了package.json文件,应用程序确实在localhost上打开,但是当这个错误弹出时,它会立即关闭。在package.json中,输入npm start时,npm run server和npm run client都会同时触发 [1] Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sen

我正在node.js和react.js上创建一个实时twitter拖缆应用程序,在npm启动时遇到了这个错误。我已经修复了package.json文件,应用程序确实在localhost上打开,但是当这个错误弹出时,它会立即关闭。在package.json中,输入npm start时,npm run server和npm run client都会同时触发

[1] Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
[1]     at new NodeError (node:internal/errors:329:5)
[1]     at ServerResponse.setHeader (node:_http_outgoing:573:11)
[1]     at ServerResponse.header (D:\UCL\real-time-tweet-streamer\node_modules\express\lib\response.js:771:10)
[1]     at ServerResponse.send (D:\UCL\real-time-tweet-streamer\node_modules\express\lib\response.js:170:12) 
[1]     at ServerResponse.json (D:\UCL\real-time-tweet-streamer\node_modules\express\lib\response.js:267:15) 
[1]     at ServerResponse.send (D:\UCL\real-time-tweet-streamer\node_modules\express\lib\response.js:158:21) 
[1]     at D:\UCL\real-time-tweet-streamer\server\server.js:77:9
[1]     at processTicksAndRejections (node:internal/process/task_queues:94:5) {
[1]   code: 'ERR_HTTP_HEADERS_SENT'
[1] }
[1] npm ERR! code 1
[1] npm ERR! path D:\UCL\real-time-tweet-streamer
[1] npm ERR! command failed
[1] npm ERR! command C:\WINDOWS\system32\cmd.exe /d /s /c node server/server.js
下面是server.js中的代码

const express = require("express");
const bodyParser = require("body-parser");
const util = require("util");
const request = require("request");
const path = require("path");
const socketIo = require("socket.io");
const http = require("http");

const app = express();
let port = process.env.PORT || 3000;
const post = util.promisify(request.post);
const get = util.promisify(request.get);

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

const server = http.createServer(app);
const io = socketIo(server);

const BEARER_TOKEN = process.env.TWITTER_BEARER_TOKEN;

let timeout = 0;

const streamURL = new URL(
  "https://api.twitter.com/2/tweets/search/stream?tweet.fields=context_annotations&expansions=author_id"
);

const rulesURL = new URL(
  "https://api.twitter.com/2/tweets/search/stream/rules"
);

const errorMessage = {
  title: "Please Wait",
  detail: "Waiting for new Tweets to be posted...",
};

const authMessage = {
  title: "Could not authenticate",
  details: [
    `Please make sure your bearer token is correct. 
      If using Glitch, remix this app and add it to the .env file`,
  ],
  type: "https://developer.twitter.com/en/docs/authentication",
};

const sleep = async (delay) => {
  return new Promise((resolve) => setTimeout(() => resolve(true), delay));
};

app.get("/api/rules", async (req, res) => {
  if (!BEARER_TOKEN) {
    res.status(400).send(authMessage);
  }

  const token = BEARER_TOKEN;
  const requestConfig = {
    url: rulesURL,
    auth: {
      bearer: token,
    },
    json: true,
  };

  try {
    const response = await get(requestConfig);

    if (response.statusCode !== 200) {
      if (response.statusCode === 403) {
        res.status(403).send(response.body);
      } else {
        throw new Error(response.body.error.message);
      }
    }

    res.send(response);
  } catch (e) {
    res.send(e);
  }
});

app.post("/api/rules", async (req, res) => {
  if (!BEARER_TOKEN) {
    res.status(400).send(authMessage);
  }

  const token = BEARER_TOKEN;
  const requestConfig = {
    url: rulesURL,
    auth: {
      bearer: token,
    },
    json: req.body,
  };

  try {
    const response = await post(requestConfig);

    if (response.statusCode === 200 || response.statusCode === 201) {
      res.send(response);
    } else {
      throw new Error(response);
    }
  } catch (e) {
    res.send(e);
  }
});

const streamTweets = (socket, token) => {
  let stream;

  const config = {
    url: streamURL,
    auth: {
      bearer: token,
    },
    timeout: 31000,
  };

  try {
    const stream = request.get(config);

    stream
      .on("data", (data) => {
        try {
          const json = JSON.parse(data);
          if (json.connection_issue) {
            socket.emit("error", json);
            reconnect(stream, socket, token);
          } else {
            if (json.data) {
              socket.emit("tweet", json);
            } else {
              socket.emit("authError", json);
            }
          }
        } catch (e) {
          socket.emit("heartbeat");
        }
      })
      .on("error", (error) => {
        // Connection timed out
        socket.emit("error", errorMessage);
        reconnect(stream, socket, token);
      });
  } catch (e) {
    socket.emit("authError", authMessage);
  }
};

const reconnect = async (stream, socket, token) => {
  timeout++;
  stream.abort();
  await sleep(2 ** timeout * 1000);
  streamTweets(socket, token);
};

io.on("connection", async (socket) => {
  try {
    const token = BEARER_TOKEN;
    io.emit("connect", "Client connected");
    const stream = streamTweets(io, token);
  } catch (e) {
    io.emit("authError", authMessage);
  }
});

console.log("NODE_ENV is", process.env.NODE_ENV);

if (process.env.NODE_ENV === "production") {
  app.use(express.static(path.join(__dirname, "../build")));
  app.get("*", (request, res) => {
    res.sendFile(path.join(__dirname, "../build", "index.html"));
  });
} else {
  port = 3001;
}

server.listen(port, () => console.log(`Listening on port ${port}`));

如果有人能帮助我了解错误所在以及可能存在的解决方案,我将不胜感激。

在您发送响应的每个位置之后,您需要返回
,这样您的函数就不会继续执行并导致它尝试发送另一个响应。我在
/api/rules
路由中看到多个地方,在发送响应后需要添加
返回
,因为如果不添加,即使您已经发送了响应,它也会执行
res.end(response)
。这就是导致您看到的错误的原因。

这工作非常好!现在,当应用程序查找新tweet时,控制台中会出现一个不同的错误。错误:CORS策略已阻止从源“”访问“”处的XMLHttpRequest:请求的资源上不存在“Access Control Allow origin”标头。@VanshAmbashta-这将是一个新问题的主题。如果您试图从不同于API主机域的网页访问API,则需要启用CORs支持。如果你需要帮助,最好研究一下如何做,然后开始一个新问题。请查看上面的链接