aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Discord-Bots

Discord Bot Event Listener: Leitfaden zu Gateway und Intents

Einen discord bot event Listener zu schreiben ist der Schritt, der deinen Bot von einer statischen Befehlsmaschine in eine Anwendung verwandelt, die in Echtzeit reagiert. Discord leitet alles, was auf einem Server passiert — eine gesendete Nachricht, ein beitretendes Mitglied, eine hinzugefügte Reaktion — als Event über eine dauerhafte WebSocket-Verbindung an deinen Bot weiter. In diesem Artikel erkläre ich Schritt für Schritt, wie der Event-Fluss funktioniert, warum Gateway Intents zwingend sind und wie du eine solide Event-Listener-Struktur aufbaust, alles mit discord.js.

Was ist die Gateway und wie funktioniert der Event-Fluss?

Discord-Bots kommunizieren tatsächlich über zwei getrennte Kanäle. Aktionen wie eine Nachricht senden oder einen Kanal erstellen erfolgen über HTTP-Anfragen an die REST-API. Im Gegensatz dazu läuft das Mithören dessen, was passiert, über eine dauerhafte WebSocket-Verbindung namens Gateway.

Der Ablauf ist folgender: Beim Start verbindet sich dein Bot mit der Gateway und authentifiziert sich mit seinem Token (IDENTIFY). Discord erwartet regelmäßige Heartbeats, um sicherzustellen, dass die Verbindung noch lebt. Sobald die Verbindung steht, pusht Discord bei jedem Ereignis auf einem Server ein Event-Paket (zum Beispiel MESSAGE_CREATE) an deinen Bot. Die Bibliothek fängt dieses Rohpaket ab, analysiert es und löst die von dir registrierte Listener-Funktion aus.

Deshalb "stellt ein eventbasierter Bot nie eine Frage und wartet auf eine Antwort"; stattdessen empfängt er Events nach einem Push-Modell über eine durchgehend offene Leitung. Die Architektur des Bots sollte um diese Tatsache herum aufgebaut werden.

Intents: der Schlüssel, der bestimmt, worauf du hören kannst

Seit 2020 schränkt Discord über Gateway Intents ein, welche Event-Typen Bots erhalten. Ein Intent ist ein Berechtigungs-Flag, das sagt "ich möchte Events dieser Kategorie empfangen". Wenn du keine Events anforderst, die du nicht brauchst, sinken sowohl der Netzwerkverkehr als auch der Speicherverbrauch; wichtiger noch, du hast keinen Zugriff auf irrelevante Daten.

Wenn du die Intents nicht explizit deklarierst, erreichen die entsprechenden Events deinen Bot nie. Die Antwort auf die häufige Frage "warum wird mein Message-Event nicht ausgelöst?" ist meist ein fehlender Intent. Einige Intents gelten als privilegiert und müssen sowohl im Discord Developer Portal aktiviert als auch im Code deklariert werden:

  • GuildMembers — Beitritt/Austritt von Mitgliedern, Mitgliederliste (privilegiert).
  • MessageContent — Zugriff auf den Textinhalt von Nachrichten (privilegiert).
  • GuildPresences — Online-Status und Aktivität (privilegiert).

Für Bots auf mehr als 100 Servern musst du für privilegierte Intents eine Verifizierung von Discord einholen. Deinen Bot auf die Intents zu beschränken, die er wirklich braucht, ist daher sowohl gute Praxis als auch eine Voraussetzung für die Skalierung.

Deinen ersten Event Listener einrichten

Ein minimales Bot-Grundgerüst mit discord.js v14 sieht so aus. Wir erstellen das Client-Objekt mit den erforderlichen Intents und hängen dann Listener an Events:

const { Client, GatewayIntentBits, Events } = require('discord.js');

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
});

// Wird einmal ausgelöst, sobald die Verbindung bereit ist
client.once(Events.ClientReady, (c) => {
  console.log(`Eingeloggt als: ${c.user.tag}`);
});

// Wird bei jeder neuen Nachricht ausgelöst
client.on(Events.MessageCreate, (message) => {
  if (message.author.bot) return;            // Nachrichten von Bots ignorieren
  if (message.content === '!ping') {
    message.reply('Pong!');
  }
});

client.login(process.env.DISCORD_TOKEN);

Hier gibt es zwei wichtige Unterschiede. client.once führt den Listener nur einmal aus — ideal für Lebenszyklus-Events, die nur einmal auftreten, wie ClientReady. client.on hingegen wird bei jedem Auftreten erneut ausgelöst. Die Prüfung message.author.bot verhindert außerdem, dass sich Bots gegenseitig in eine Endlosschleife auslösen; das ist eine leicht übersehene, aber kritische Absicherung.

Häufig genutzte Events und ihre korrekte Verwendung

Ein echter Bot reagiert nicht auf ein einzelnes Event, sondern auf mehrere gleichzeitig. Die Events, mit denen du am häufigsten arbeitest, sind:

  • GuildMemberAdd — für eine Willkommensnachricht oder automatische Rolle, wenn ein neues Mitglied beitritt (erfordert den GuildMembers-Intent).
  • InteractionCreate — der moderne, empfohlene Weg für Slash-Commands, Buttons und Menüs.
  • MessageReactionAdd — für Reaction-Role-Systeme.
  • GuildCreate — wenn der Bot zu einem neuen Server hinzugefügt wird, für die Einrichtung.

In modernen Bots solltest du die Befehlslogik eher auf InteractionCreate und Slash-Commands aufbauen als auf MessageCreate, da MessageContent ein privilegierter Intent ist und Discord langfristig keine auf Nachrichteninhalt basierenden Befehle fördert.

Deine Event-Struktur skalierbar halten

Alle Listener in eine einzige Datei zu stopfen, wird mit wachsendem Bot unhandhabbar. Ein solider Ansatz ist der Aufbau eines Event-Handlers, der jedes Event in eine eigene Datei legt. Jede Datei exportiert den Namen des Events und die auszuführende Funktion:

// events/messageCreate.js
const { Events } = require('discord.js');

module.exports = {
  name: Events.MessageCreate,
  once: false,
  execute(message) {
    if (message.author.bot) return;
    // ... Logik
  },
};
// der Teil, der die Listener automatisch lädt
const fs = require('node:fs');
const path = require('node:path');

const eventsPath = path.join(__dirname, 'events');
const files = fs.readdirSync(eventsPath).filter((f) => f.endsWith('.js'));

for (const file of files) {
  const event = require(path.join(eventsPath, file));
  if (event.once) {
    client.once(event.name, (...args) => event.execute(...args));
  } else {
    client.on(event.name, (...args) => event.execute(...args));
  }
}

Dank dieser Struktur ist das Hinzufügen eines neuen Events so einfach wie das Ablegen einer Datei im Ordner events/. Der Code bleibt lesbar, die Verantwortung jedes Events ist getrennt, und das Debuggen wird deutlich einfacher.

Häufige Fehler

Die häufigsten Fallstricke bei Event Listenern sind: (1) Fehlende Intents — der Hauptgrund, warum ein Event nicht ausgelöst wird. (2) Nur die Events wählen, die du wirklich brauchst, statt auf zu viele zu hören. (3) Fehler nicht abfangen, wenn du Netzwerkanfragen innerhalb eines Listeners mit await abwartest; ein einziger unbehandelter Fehler kann den Bot zum Absturz bringen. Listener in ein try/catch zu hüllen und den Bot unter einem Process Manager (wie PM2) laufen zu lassen, verbessert die Stabilität in der Produktion deutlich.

Häufig gestellte Fragen

Reicht es, den Intent allein im Code hinzuzufügen?

Für privilegierte Intents nicht. Du musst MessageContent, GuildMembers und GuildPresences im Code deklarieren und sie in den Bot-Einstellungen im Discord Developer Portal aktivieren. Fehlt eines davon, kommen die Events nicht an.

Was ist der Unterschied zwischen client.on und client.once?

client.on führt den Listener bei jeder Wiederkehr des Events aus; client.once führt ihn nur beim ersten Mal aus und entfernt den Listener danach automatisch. Für ein einmaliges Event wie ClientReady ist once die richtige Wahl.

Der Nachrichteninhalt kommt leer zurück — warum?

Höchstwahrscheinlich fehlt der MessageContent-Intent. Ohne diesen privilegierten Intent kommt message.content leer an; der Inhalt ist nur für Nachrichten gefüllt, in denen der Bot erwähnt wird oder die DMs sind.

Möchtest du eine solide Event-Architektur für deinen Bot? Von Gateway Intents bis zu einer skalierbaren Handler-Struktur entwickle ich Discord-Bots von Anfang bis Ende. Um dein Projekt zu besprechen, nimm Kontakt mit mir auf.

Bu kategorideki tüm yazılar →

Devamı için