Erstellen eines Kurzlinkdienstes mit Nest.js
Takashi Yamamoto
Infrastructure Engineer · Leapcell

Was ist ein Kurzlink?
Wenn Sie im Internet surfen, haben Sie wahrscheinlich oft Links wie t.cn/A67x8Y
oder bit.ly/3z4aBc
gesehen. Sie sind normalerweise recht kurz, und ein Klick darauf leitet Sie zu einer Seite mit einer völlig anderen Domain als der ursprünglichen weiter.
Diese Links sind Kurzlinks.
Warum werden Kurzlinks benötigt?
Kurzlinks entstanden in den frühen Tagen von Twitter, als es strenge Zeichenbeschränkungen gab. Zu dieser Zeit war ihr Hauptzweck, Zeichen zu sparen und zu verhindern, dass Links wertvollen Platz beanspruchen.
Als Kurzlinks weiter verbreitet wurden, wurde die "Kürze" des Links selbst weniger wichtig. Es wurden weitere Verwendungszwecke entwickelt:
- Datenanalyse: Kurzlinkdienste bieten oft Klickstatistiken, die es den Benutzern erleichtern, die Anzahl der Klicks und die Effektivität der Verbreitung des Links zu verstehen.
- Blockierung umgehen: Einige Software, wie Safari und bestimmte E-Mail-Clients, ist sehr streng bei der Linkverfolgung und bereinigt Tracking-Parameter automatisch aus Links. Die Verwendung eines Kurzlinks kann dieses Problem vermeiden.
- Ästhetik: Kurzlinks sind sauber und prägnant, wodurch sie sich für die gemeinsame Nutzung in reinen Text-Szenarien wie sozialen Medien und Textnachrichten eignen und die Formatierung vereinfachen.
Wie Kurzlinks funktionieren
Der Kurzlink-Prozess ist in zwei Schritte unterteilt:
Erstellen eines Kurzlinks:
- Ein Benutzer sendet eine lange URL an unseren Dienst.
- Unser Dienst generiert eine eindeutige Kennung dafür (z. B.
aK8xLq
). - Der Dienst speichert die Zuordnung dieses "Codes" und der ursprünglichen langen URL in einer Datenbank.
- Die Kennung wird an den Benutzer zurückgegeben.
Umleitung zur ursprünglichen Verknüpfung von einem Kurzlink:
- Wenn jemand auf
https://short.url/aK8xLq
klickt, sendet der Browser eine Anfrage an unseren Server. - Der Server analysiert die Kennung
aK8xLq
aus dem URL-Pfad. - Der Server fragt die Datenbank nach dieser Kennung ab, um die entsprechende ursprüngliche lange URL zu finden.
- Der Server gibt einen Weiterleitungsstatuscode (301/302) an den Browser zurück und fügt die ursprüngliche lange URL im Feld
Location
des Antwortheaders hinzu. - Nach Erhalt dieser Antwort leitet der Browser automatisch zu der im Feld
Location
angegebenen langen URL weiter.
Wie die Kennung generiert wird
Hash-Algorithmen werden üblicherweise für die Generierung verwendet.
- Hash generieren: Verwenden Sie die lange URL selbst oder die lange URL plus einen "Salt" (eine zufällige Zeichenkette) als Eingabe für einen Hash-Algorithmus wie MD5 oder SHA1, um eine Digest zu generieren.
- Segment abschneiden: Der vorherige Schritt generiert eine Zeichenkette. Wir können ein Segment davon (z. B. die ersten 6 Zeichen) als Kurzcode nehmen.
- Kollisionen behandeln: Zwei verschiedene lange URLs könnten denselben Kurzcode generieren. Bevor wir einen Kurzcode in der Datenbank speichern, müssen wir prüfen, ob er bereits vorhanden ist. Wenn dies der Fall ist, können wir ein anderes Segment nehmen oder den Kurzcode neu generieren.
Einen eigenen Kurzlinkdienst erstellen
Ein Kurzlinkdienst besteht aus zwei Hauptfunktionsmodulen:
- Nest.js
- PostgreSQL als Datenbank
1. Projekt initialisieren
Installieren Sie das Nest.js CLI:
npm i -g @nestjs/cli
Erstellen Sie ein neues Projekt mit dem CLI:
nest new url-shortener
Dadurch wird ein neuer Ordner namens url-shortener
erstellt und alle notwendigen Abhängigkeiten installiert. Öffnen Sie dieses Verzeichnis in Ihrem bevorzugten Editor, um mit dem Codieren zu beginnen.
2. Verbindung zur PostgreSQL-Datenbank herstellen
Als Nächstes integrieren wir eine PostgreSQL-Datenbank. Gemäß der offiziellen Empfehlung verwenden wir TypeORM als ORM. Die Aufgabe eines ORM ist die Integration der Datenbank in unseren Code.
Abhängigkeiten installieren
npm install @nestjs/typeorm typeorm pg # Für PostgreSQL-Integration npm install @nestjs/config class-validator class-transformer # Für die Validierung von Schnittstellenparametern
Datenbank einrichten
Um die Schritte zu vereinfachen, installieren und erstellen wir keine Datenbank lokal. Stattdessen beantragen wir eine Online-Datenbank.
Wir können mit einem Klick eine kostenlose Datenbank auf Leapcell erhalten.
Nachdem Sie sich auf der Website registriert haben, klicken Sie auf "Create Database".
Geben Sie einen Datenbanknamen ein und wählen Sie eine Bereitstellungsregion, um die PostgreSQL-Datenbank zu erstellen.
Auf der neuen Seite sehen Sie die erforderlichen Informationen zur Verbindung mit der Datenbank. Unten sehen Sie ein Bedienfeld, über das Sie die Datenbank direkt auf der Webseite lesen und ändern können.
Konfigurieren der Datenbankverbindung
Öffnen Sie die Datei src/app.module.ts
und importieren Sie TypeOrmModule
.
Füllen Sie die Verbindungsinformationen anhand der von Leapcell erhaltenen Datenbankanmeldeinformationen aus. Beachten Sie, dass ssl
auf true
gesetzt sein muss, da die Verbindung sonst fehlschlägt.
import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { AppController } from './app.controller'; import { AppService } from './app.service'; @Module({ imports: [ TypeOrmModule.forRoot({ type: 'postgres', host: 'your_postgres_host', port: 5432, username: 'your_postgres_username', // Ersetzen Sie dies durch Ihren PostgreSQL-Benutzernamen password: 'your_postgres_password', // Ersetzen Sie dies durch Ihr PostgreSQL-Passwort database: 'your_postgres_db', // Ersetzen Sie dies durch Ihren Datenbanknamen schema: 'myschema', entities: [__dirname + '/**/*.entity{.ts,.js}'], synchronize: true, // In der Entwicklung auf true setzen; synchronisiert automatisch die DB-Struktur ssl: true, // Erforderlich für Dienste wie Leapcell }), ], controllers: [AppController], providers: [AppService], }) export class AppModule {}
Erstellen des Kurzlink-Moduls
Erstellen Sie als Nächstes ein Modul zur Verwaltung von Kurzlinks.
Sie können die notwendigen Dateien mit dem Nest CLI schnell generieren:
nest generate resource short-link
Danach müssen wir die ShortLink
-Entitätsdatei erstellen, um sie mit der Datenbank zu verbinden. Erstellen Sie eine Datei namens short-link.entity.ts
im Verzeichnis src/short-link
:
// src/short-link/short-link.entity.ts import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, Index } from 'typeorm'; @Entity() export class ShortLink { @PrimaryGeneratedColumn('uuid') id: string; @Column({ unique: true }) @Index() // Erstellen Sie einen Index für shortCode, um Abfragen zu beschleunigen shortCode: string; @Column({ type: 'text' }) longUrl: string; @CreateDateColumn() createdAt: Date; }
Erstellen Sie als Nächstes ein DTO (Data Transfer Object). Das DTO wird verwendet, um eingehende Anforderungsdaten zu validieren und sicherzustellen, dass wir eine URL in einem gültigen Format erhalten.
// src/short-link/dto/create-short-link.dto.ts import { IsUrl } from 'class-validator'; export class CreateShortLinkDto { @IsUrl({}, { message: 'Bitte geben Sie eine gültige URL an.' }) url: string; }
Jetzt müssen wir uns mit der Datenbank verbinden.
Registrieren Sie TypeOrmModule
im ShortLinkModule
: Öffnen Sie src/short-link/short-link.module.ts
und importieren Sie TypeOrmModule.forFeature([ShortLink])
.
// 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'; @Module({ imports: [TypeOrmModule.forFeature([ShortLink])], controllers: [ShortLinkController], providers: [ShortLinkService], }) export class ShortLinkModule {}
Gehen Sie auf die Seite mit den Datenbankdetails auf Leapcell und führen Sie den folgenden Befehl im Webeditor aus, um die entsprechende Tabelle zu generieren:
CREATE TABLE "short_link" ( "id" UUID PRIMARY KEY DEFAULT gen_random_uuid(), "shortCode" VARCHAR(255) NOT NULL UNIQUE, "longUrl" TEXT NOT NULL, "createdAt" TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX "IDX_short_code" ON "short_link" ("shortCode");
Erstellen des Kurzlinkdienstes
Der ShortLinkService
ist für die gesamte Geschäftslogik im Zusammenhang mit Kurzlinks zuständig. Öffnen Sie src/short-link/short-link.service.ts
und fügen Sie den folgenden Code hinzu:
// src/short-link/short-link.service.ts import { Injectable, InternalServerErrorException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { ShortLink } from './short-link.entity'; // Korrigierter Importpfad import * as crypto from 'crypto'; @Injectable() export class ShortLinkService { constructor( @InjectRepository(ShortLink) private readonly shortLinkRepository: Repository<ShortLink> ) {} // Link anhand des shortCode finden async findOneByCode(shortCode: string): Promise<ShortLink | null> { return this.shortLinkRepository.findOneBy({ shortCode }); } // Einen neuen Kurzlink erstellen async create(longUrl: string): Promise<ShortLink> { // Prüfen, ob der lange Link bereits existiert; wenn ja, diesen zurückgeben, um Duplikate zu vermeiden const existingLink = await this.shortLinkRepository.findOneBy({ longUrl }); if (existingLink) { return existingLink; } // Einen eindeutigen shortCode generieren const shortCode = await this.generateUniqueShortCode(longUrl); // In die Datenbank speichern const newLink = this.shortLinkRepository.create({ longUrl, shortCode, }); return this.shortLinkRepository.save(newLink); } /** * Einen gehashten Kurzcode generieren und Kollisionen behandeln * @param longUrl Die ursprüngliche URL */ private async generateUniqueShortCode(longUrl: string): Promise<string> { const HASH_LENGTH = 7; // Länge unseres gewünschten Kurzcodes definieren let attempt = 0; // Versuchs Zähler // Eine maximale Anzahl von Versuchen festlegen, um eine Endlosschleife zu verhindern while (attempt < 10) { // Salted Hash: die Versuchsnummer als "Salt" hinzufügen, um jedes Mal einen anderen Hash zu gewährleisten const salt = attempt > 0 ? String(attempt) : ''; const hash = crypto .createHash('sha256') .update(longUrl + salt) .digest('base64url') // base64url für URL-sichere Zeichen verwenden .substring(0, HASH_LENGTH); const linkExists = await this.findOneByCode(hash); if (!linkExists) { // Wenn der Hash-Code nicht in der Datenbank existiert, ist er eindeutig und kann zurückgegeben werden return hash; } // Wenn er existiert (eine Kollision ist aufgetreten), den Versuchszähler erhöhen, und die Schleife wird fortgesetzt attempt++; } // Wenn nach mehreren Versuchen kein eindeutiger Code gefunden werden kann, einen Fehler auslösen throw new InternalServerErrorException( 'Konnte keinen eindeutigen Kurzlink generieren. Bitte versuchen Sie es erneut.' ); } }
Erstellen des Kurzlink-Controllers
Der Controller ist für die Bearbeitung von HTTP-Anfragen, den Aufruf des Dienstes und die Rückgabe einer Antwort zuständig. Öffnen Sie src/short-link/short-link.controller.ts
und fügen Sie den folgenden Code hinzu:
// src/short-link/short-link.controller.ts import { Controller, Get, Post, Body, Param, Res, NotFoundException } from '@nestjs/common'; import { Response } from 'express'; import { ShortLinkService } from './short-link.service'; import { CreateShortLinkDto } from './dto/create-short-link.dto'; @Controller() export class ShortLinkController { constructor( private readonly shortLinkService: ShortLinkService, ) {} @Post('shorten') async createShortLink(@Body() createShortLinkDto: CreateShortLinkDto) { const link = await this.shortLinkService.create(createShortLinkDto.url); return { shortCode: link.shortCode, }; } @Get(':shortCode') async redirect(@Param('shortCode') shortCode: string, @Res() res: Response) { const link = await this.shortLinkService.findOneByCode(shortCode); if (!link) { throw new NotFoundException('Kurzlink nicht gefunden.'); } // Weiterleitung durchführen return res.redirect(301, link.longUrl); } }
Projekt starten
DTO-Validierung in src/main.ts
aktivieren:
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { ValidationPipe } from '@nestjs/common'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalPipes(new ValidationPipe()); // Diese Zeile hinzufügen await app.listen(3000); } bootstrap();
Führen Sie den folgenden Befehl im Terminal aus, um das Projekt zu starten:
npm run start:dev
Führen Sie in Ihrer Konsole den folgenden Befehl aus, um einen Kurzlink zu erstellen:
curl -X POST http://localhost:3000/shorten \ -H "Content-Type: application/json" \ -d '{"url": "https://www.google.com/search?q=nestjs+url+shortener"}' # Antwort: {"shortCode":"some-hash"}
Zugriff auf den Kurzlink:
Verwenden Sie den im vorherigen Schritt zurückgegebenen shortCode
, um die vollständige URL http://localhost:3000/some-hash
zu erstellen, und öffnen Sie sie in Ihrem Browser. Sie werden automatisch zur Google-Suchseite weitergeleitet.
Sie können diesen Kurzlinkdienst weiter verbessern, z. B. indem Sie die Anzahl der Besuche, die IP-Adressen der Besucher usw. protokollieren.
Den Kurzlinkdienst online bereitstellen
Jetzt fragen Sie sich vielleicht, wie kann ich diesen Dienst online bereitstellen, damit meine Kurzlinks im Internet geteilt werden können?
Erinnern Sie sich an Leapcell, das wir zur Erstellung der Datenbank verwendet haben? Leapcell kann mehr als nur Datenbanken erstellen; es ist auch eine Web-App-Hosting-Plattform, die Projekte in verschiedenen Sprachen und Frameworks hosten kann, einschließlich Nest.js natürlich.
Befolgen Sie die untenstehenden Schritte:
- Pushen Sie Ihr Projekt auf GitHub. Sie können sich auf GitHubs offizielle Dokumentation für die Schritte beziehen. Leapcell wird den Code später aus Ihrem GitHub-Repository ziehen.
- Klicken Sie auf der Leapcell-Seite auf "Create Service".
- Nach der Auswahl Ihres Nest.js-Repos sehen Sie, dass Leapcell die notwendigen Konfigurationen automatisch ausgefüllt hat.
- Klicken Sie unten auf "Submit", um die Bereitstellung zu starten. Die Bereitstellung wird schnell abgeschlossen und Sie kehren zur Homepage der Bereitstellung zurück. Hier sehen wir, dass Leapcell eine Domain bereitstellt. Dies ist die Online-Adresse für Ihren Kurzlinkdienst.
Nun ist Ihr Kurzlinkdienst live und jeder kann Ihre Kurzlinks im Internet aufrufen.