Klickverfolgung zum Nest.js Short-Link-Service hinzufügen
Emily Parker
Product Engineer · Leapcell

Im vorherigen Artikel haben wir einen einfachen Short-Link-Service erstellt.
Um ein umfassender Short-Link-Service zu werden, ist es notwendig, Funktionalitäten zur Datenanalyse hinzuzufügen. Datenanalyse ist einer der Kernwerte eines Short-Link-Services. Durch die Verfolgung von Link-Klicks können wir die Effektivität der Verbreitung, Benutzerprofile und andere Informationen verstehen.
Als Nächstes werden wir Klickverfolgungsfunktionen zu unserem Service hinzufügen und die Zeit-, IP-Adress- und Geräteinformationen für jeden Klick aufzeichnen.
1. Erstellen der Datenbankentität für einen Klick-Datensatz
Zuerst benötigen wir eine neue Datenbanktabelle, um jeden Klick-Datensatz zu speichern. Ebenso definieren wir seine Struktur durch die Erstellung einer TypeORM-Entität.
Erstellen Sie einen neuen Ordner namens click
im src
-Verzeichnis und erstellen Sie darin eine click.entity.ts
-Datei:
// src/click/click.entity.ts import { ShortLink } from '../short-link/short-link.entity'; import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, ManyToOne, JoinColumn, } from 'typeorm'; @Entity() export class Click { @PrimaryGeneratedColumn('uuid') id: string; // Establish a many-to-one relationship with the ShortLink entity // This means one short link can correspond to many click records @ManyToOne(() => ShortLink, (shortLink) => shortLink.clicks) @JoinColumn({ name: 'shortLinkId' }) // Creates a foreign key column in the database shortLink: ShortLink; @CreateDateColumn() clickedAt: Date; @Column({ type: 'varchar', length: 45 }) // To store IPv4 or IPv6 addresses ipAddress: string; @Column({ type: 'text' }) userAgent: string; }
Erklärung:
@ManyToOne
: Dieser Dekorator stellt die Beziehung zwischenClick
undShortLink
her. Viele (Viele) Klicks können einem (Einen) Shortlink zugeordnet werden.@JoinColumn
: Gibt den Namen der Fremdschlüsselspalte an, die zur Verknüpfung der beiden Tabellen auf Datenbankebene verwendet wird.
2. Aktualisieren der ShortLink
-Entität
Um alle Klick-Datensätze eines Shortlinks abfragen zu können, müssen wir auch die Datei short-link.entity.ts
aktualisieren, um eine bidirektionale Beziehung herzustellen.
Öffnen Sie src/short-link/short-link.entity.ts
und fügen Sie die clicks
-Eigenschaft hinzu:
// src/short-link/short-link.entity.ts import { Click } from '../click/click.entity'; // Import the Click entity import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, Index, OneToMany, } from 'typeorm'; @Entity() export class ShortLink { @PrimaryGeneratedColumn('uuid') id: string; // ... other existing fields ... @Column({ unique: true }) @Index() shortCode: string; @Column({ type: 'text' }) longUrl: string; @CreateDateColumn() createdAt: Date; // New property @OneToMany(() => Click, (click) => click.shortLink) clicks: Click[]; }
Erklärung:
@OneToMany
: Stellt eine Eins-zu-Viele-Beziehung vonShortLink
zuClick
her. Ein (Ein) Shortlink kann viele (Viele) Klick-Datensätze haben.
3. Erstellen des Moduls und der Logik für den Click-Service
Genau wie bei ShortLink
erstellen wir ein dediziertes Modul und einen Service für Click
, um die zugehörige Logik zu verarbeiten und die Code-Modularität aufrechtzuerhalten.
Verwenden Sie die Nest CLI, um die erforderlichen Dateien schnell zu generieren:
nest generate resource click
Konfigurieren von ClickModule
Öffnen Sie src/click/click.module.ts
, importieren Sie TypeOrmModule
und registrieren Sie die Click
-Entität.
// src/click/click.module.ts import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { ClickService } from './click.service'; import { Click } from './click.entity'; @Module({ imports: [TypeOrmModule.forFeature([Click])], providers: [ClickService], exports: [ClickService], // Export ClickService, damit es von anderen Modulen verwendet werden kann }) export class ClickModule {}
Implementieren von ClickService
Öffnen Sie src/click/click.service.ts
und schreiben Sie die Logik für die Aufzeichnung von Klicks.
// src/click/click.service.ts import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { Click } from './click.entity'; import { ShortLink } from '../short-link/short-link.entity'; @Injectable() export class ClickService { constructor( @InjectRepository(Click) private readonly clickRepository: Repository<Click> ) {} async recordClick(shortLink: ShortLink, ipAddress: string, userAgent: string): Promise<Click> { const newClick = this.clickRepository.create({ shortLink, ipAddress, userAgent, }); return this.clickRepository.save(newClick); } }
4. Klickverfolgung während der Weiterleitung integrieren
Jetzt integrieren wir die Verfolgungslogik in die redirect
-Methode des ShortLinkController
.
Aktualisieren von ShortLinkModule
Zuerst muss ShortLinkModule
ClickModule
importieren, um ClickService
verwenden zu können.
// src/short-link/short-link.module.ts import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { ShortLinkController } from './short-link.controller'; import { ShortLinkService } from './short-link.service'; import { ShortLink } from './short-link.entity'; import { ClickModule } from '../click/click.module'; // Import ClickModule @Module({ imports: [TypeOrmModule.forFeature([ShortLink]), ClickModule], // Add ClickModule controllers: [ShortLinkController], providers: [ShortLinkService], }) export class ShortLinkModule {}
Ändern von ShortLinkController
Öffnen Sie src/short-link/short-link.controller.ts
, injizieren Sie ClickService
und rufen Sie diese in der redirect
-Methode auf.
// src/short-link/short-link.controller.ts import { Controller, Get, Post, Body, Param, Res, NotFoundException, Req } from '@nestjs/common'; import { Response, Request } from 'express'; import { ShortLinkService } from './short-link.service'; import { CreateShortLinkDto } from './dto/create-short-link.dto'; import { ClickService } from '../click/click.service'; // Import ClickService @Controller() export class ShortLinkController { constructor( private readonly shortLinkService: ShortLinkService, private readonly clickService: ClickService // Inject ClickService ) {} // ... createShortLink method remains unchanged ... @Post('shorten') // ... @Get(':shortCode') async redirect( @Param('shortCode') shortCode: string, @Res() res: Response, @Req() req: Request // Inject the Express Request object ) { const link = await this.shortLinkService.findOneByCode(shortCode); if (!link) { throw new NotFoundException('Short link not found.'); } // Record the click asynchronously without waiting for it to complete, // to avoid delaying the user's redirection this.clickService.recordClick(link, req.ip, req.get('user-agent') || ''); // Perform the redirect return res.redirect(301, link.longUrl); } }
Wichtige Änderungen:
- Wir haben
ClickService
injiziert. - In der
redirect
-Methode haben wir dasexpress
Request
-Objekt über den@Req()
-Dekorator erhalten. - Aus dem
req
-Objekt haben wirreq.ip
(IP-Adresse) undreq.get('user-agent')
(Geräte- und Browserinformationen) abgerufen. - Wir haben
this.clickService.recordClick()
aufgerufen, um den Klick-Datensatz zu speichern. Hinweis: Wir haben hier keinawait
verwendet, um sicherzustellen, dass die Klickaufzeichnungsoperation die Weiterleitung nicht blockiert.
5. Statistiken anzeigen
Nachdem die Daten aufgezeichnet wurden, benötigen wir auch einen Endpunkt, um sie anzuzeigen. Fügen wir einen Statistik-Endpunkt im ShortLinkController
hinzu.
// src/short-link/short-link.controller.ts // ... (imports and constructor) @Controller() export class ShortLinkController { // ... (constructor and other methods) // New statistics endpoint @Get('stats/:shortCode') async getStats(@Param('shortCode') shortCode: string) { const linkWithClicks = await this.shortLinkService.findOneByCodeWithClicks(shortCode); if (!linkWithClicks) { throw new NotFoundException('Short link not found.'); } return { shortCode: linkWithClicks.shortCode, longUrl: linkWithClicks.longUrl, totalClicks: linkWithClicks.clicks.length, clicks: linkWithClicks.clicks.map((click) => ({ clickedAt: click.clickedAt, ipAddress: click.ipAddress, userAgent: click.userAgent, })), }; } }
Damit dieser Endpunkt funktioniert, müssen wir auch die Methode findOneByCodeWithClicks
im ShortLinkService
hinzufügen.
Öffnen Sie src/short-link/short-link.service.ts
:
// src/short-link/short-link.service.ts // ... @Injectable() export class ShortLinkService { constructor( @InjectRepository(ShortLink) private readonly shortLinkRepository: Repository<ShortLink> ) {} // ... (findOneByCode and create methods) // New method that uses relations to load the associated clicks async findOneByCodeWithClicks(shortCode: string): Promise<ShortLink | null> { return this.shortLinkRepository.findOne({ where: { shortCode }, relations: ['clicks'], // Key: Tells TypeORM to load the related clicks entity }); } }
Starten Sie nun Ihren Service neu. Nachdem Sie einen Shortlink besucht haben, können Sie eine GET
-Anfrage an http://localhost:3000/stats/your-short-code
stellen und erhalten eine JSON-Antwort ähnlich der unten, die detaillierte Klick-Datensätze enthält:
{ "shortCode": "some-hash", "longUrl": "https://www.google.com/", "totalClicks": 1, "clicks": [ { "clickedAt": "2025-09-17T23:00:00.123Z", "ipAddress": "::1", "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ..." } ] }
An diesem Punkt verfügt Ihr Short-Link-Service nun über Klickverfolgungs- und statistische Analysefunktionen!
Update für die Produktion
Da Ihr Service bereits online läuft, ist der nächste Schritt nach dem lokalen Debugging die Bereitstellung der Updates für den Produktionsserver.
Für Anwendungen, die auf Leapcell bereitgestellt werden, ist dieser Schritt sehr einfach: Sie müssen lediglich Ihren Code nach GitHub pushen, und Leapcell ruft automatisch den neuesten Code ab und aktualisiert die Anwendung.
Darüber hinaus verfügt Leapcell selbst über eine leistungsstarke integrierte Traffic-Analyse-Funktion. Selbst ohne die Implementierung der Klickverfolgung selbst können die Daten im Leapcell-Dashboard Ihnen tiefe Einblicke in die Benutzer liefern.