Saya membuat aplikasi streamer Twitter waktu nyata di node.js dan react.js dan saya menghadapi kesalahan ini pada npm start. Saya telah memperbaiki file package.json dan aplikasi terbuka di localhost, namun langsung mati saat kesalahan ini muncul. Dalam package.json, npm run server dan npm run client keduanya dipicu secara bersamaan ketika npm start dimasukkan.

[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

Berikut kode dari 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}`));

Akan sangat menghargai jika seseorang dapat membantu saya memahami di mana letak kesalahannya dan solusi apa yang mungkin ada.

0
Vansh Ambashta 12 Mei 2021, 08:54

1 menjawab

Jawaban Terbaik

Setelah setiap tempat Anda mengirim respons, Anda perlu return agar fungsi Anda tidak terus berjalan dan menyebabkannya mencoba mengirim respons lain. Saya melihat beberapa tempat di rute /api/rules di mana Anda perlu menambahkan return setelah mengirim tanggapan karena jika tidak, itu akan mengeksekusi res.end(response) meskipun Anda sudah mengirim tanggapan. Itulah yang menyebabkan kesalahan yang Anda lihat.

1
jfriend00 12 Mei 2021, 06:02