Heim  >  Artikel  >  Web-Frontend  >  Detaillierte Erläuterung des von Nodejs+Nest implementierten Kurzlink-Dienstes

Detaillierte Erläuterung des von Nodejs+Nest implementierten Kurzlink-Dienstes

青灯夜游
青灯夜游nach vorne
2021-04-30 10:48:022732Durchsuche

In diesem Artikel wird Ihnen die Methode zur Implementierung eines Kurzlink-Dienstes basierend auf dem Node-Framework Nest vorgestellt. Es hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen. Ich hoffe, es wird für alle hilfreich sein.

Detaillierte Erläuterung des von Nodejs+Nest implementierten Kurzlink-Dienstes

Empfohlenes Lernen: „nodejs-Tutorial

Jedes Mal, wenn ich zum Springen klicke, wird sich der Autor großartig fühlen zu Was führt zur richtigen Seite?

Das Prinzip der kurzen Links

Das Prinzip der kurzen Links besteht darin, kurze Links zu verlängern. Wie kann also diese kurze Zeichenfolge in eine lange Zeichenfolge umgewandelt werden? Verlässt es sich auf einen magischen Verschlüsselungsalgorithmus? Nein, wir müssen uns nur auf die Schlüssel/Wert-Zuordnungsbeziehung verlassen, um diese scheinbar magische Sache leicht zu erreichen. Mit einem Bild kann jeder den gesamten Prozess des Zugriffs auf den Kurzlink deutlich erkennen.

Detaillierte Erläuterung des von Nodejs+Nest implementierten Kurzlink-DienstesZuerst erhalten wir durch die Verarbeitung des Kurzlink-Dienstes normalerweise eine URL mit nur einer Verzeichnisebene, und dann können wir die erhaltene URL verteilen.

Dann gelangen wir auf die Benutzerseite. Nachdem der Benutzer auf den Kurzlink geklickt hat, gelangt er als Erstes nicht zur Zielseite, sondern zum Kurzlink-Dienst.

Der Kurzlink-Dienst fängt den Pfadnamen auf dem Link ab und verwendet ihn als Schlüssel, um den entsprechenden Wert in der Zuordnungsbeziehung zu finden.

Wenn der entsprechende Wert nicht gefunden werden kann, bedeutet dies, dass der Kurzlink nicht existiert oder abgelaufen ist. Wenn die Abfrage erfolgreich ist, führt der Kurzlink-Dienst direkt eine 302-Verbindung zum Ziellink im Wert durch, um einen Kurzlink-Zugriff abzuschließen.

Spezifische Implementierung

Materialien:
Fast-Nest

Gerüst, Redis

Die gesamte Implementierung ist in drei Teile unterteilt:

① Empfang langer Links

@Post('/createUrl')
async createUrl(
    @Body('url') url: string,
    @Body('type') type: string,
) {
    const shortUrl = await this.shorturlService.createUrl(url, type);
    return {
        shortUrl,
    };
}

Erstellen Sie einen createUrlim Dienst >Schnittstelle, empfangen Sie die Felder url und type und übergeben Sie sie an shorturlService, warten Sie, bis der Kurzlink generiert und dann ausgegeben wird.

② ShortKey generieren

async createUrl(url: string, type: string = 'normal') {
    const urlKey = await this.handleUrlKey();
    const dataStr = JSON.stringify({
        url,
        type
    });
    await this.client.set(urlKey, dataStr, type === 'permanent' ? -1 : 300);
    return `${Config.defaultHost}/${urlKey}`;
}

private async handleUrlKey(count?: number): Promise<string> {
    const _count = count || 1;
    const maxCount = Config.maxRetryTimes;
    if (_count >= maxCount) throw new HttpException(&#39;超过重试次数,请重新生成链接&#39;, HttpStatus.INTERNAL_SERVER_ERROR);
    const urlKey: string = Math.random().toString(36).slice(-4);
    const _url = await this.client.get(urlKey);
    if (_url) {
        return await this.handleUrlKey(_count + 1);
    }
    return urlKey;
}
createUrl接口,接收url已经type字段,并将其传入shorturlService中,等待短链接生成然后输出。

② 生成shortKey

@Get(&#39;/:key&#39;)
@Redirect(Config.defaultIndex, 302)
async getUrl(
        @Param(&#39;key&#39;) key: string,
    ) {
    if (key) {
        const url = await this.shorturlService.getUrl(key);
        return {
            url
        }
    }
}

// this.shorturlService.getUrl
async getUrl(k: string) {
    const dataStr = await this.client.get(k);
    if (!dataStr) return;
    const { url, type } = JSON.parse(dataStr);
    if (type === &#39;once&#39;) {
        await this.client.del(k);
    }
    return url;
}

首先通过Math.random().toString(36).slice(-4)获取4位随机字符串,这个将会作为短链的pathname。

在进行映射之前,我们需要对其进行唯一性判断,虽然出现的可能性不大,但是还是需要防范短链覆盖这类的问题。本服务的解决方案是重试生成,如果短链值不幸重复时将会进入重试分支,服务将会内置可重试次数,如果重试的次数超过配置的字数,本次转换将会返回失败。

除了urlcreateUrl方法还接受一个type字段,这里涉及特殊短链的特性。我们短链有三种模式:

  • normal - 普通短链接,将会在规定时间内失效
  • once - 一次性短链接,将会在规定时间内失效,被访问后自动失效
  • permanent - 长期短链接,不会自动失效,只接受手动删除

生成urlKey之后,将会与type一起转成字符串储存到redis中,并输出拼接好的短链接。

③ 接收短链接并完成目标重定向

async createUrl(url: string, type: string = &#39;normal&#39;) {
    const urlKey = await this.handleUrlKey();
    const urlID = UUID.genV4().toString();
    const dataStr = JSON.stringify({
        urlID,
        url,
        type
    });
    this.myLogger.log(`createUrl**${urlID}`, &#39;createUrl&#39;, false);
    await this.client.set(urlKey, dataStr, type === &#39;permanent&#39; ? -1 : 300);
    return `${Config.defaultHost}/${urlKey}`;
}

用户侧会获得一个类似http://localhost:8000/s/ku6a的链接,点击之后相当于是给短链接服务发送了一个GET请求。

服务接收到请求之后获取链接中key字段的值,也就是ku6a这个字符串,利用它查找Redis中的映射关系。

这里有两个分支,一个是在Redis中无法查询到相关的值,服务则认为短链接已经失效会直接return,因为getUrl返回了空值,重定向装饰器会将本次请求重定向到默认的目标链接中。

如果在Redis中顺利查到相关的值,则会读取其中的urltypeErhalten Sie zunächst eine 4-stellige Zufallszeichenfolge über Math.random().toString(36).slice(-4) , dies wird als Pfadname des Kurzlinks verwendet.

Vor der Kartierung müssen wir die Einzigartigkeit beurteilen. Auch wenn dies unwahrscheinlich ist, müssen wir uns dennoch vor Problemen wie der Kurzkettenabdeckung schützen. Die Lösung dieses Dienstes besteht darin, die Generierung erneut zu versuchen. Wenn der Wert der kurzen Kette wiederholt wird, wird der Dienst über eine integrierte Anzahl von Wiederholungsversuchen verfügen. Diese Konvertierung führt zu einem Fehler.

Zusätzlich zu url akzeptiert die Methode createUrl auch ein Feld type, das die Eigenschaften spezieller Kurzlinks beinhaltet. Wir haben drei Modi für Kurzlinks:

  • normal – normale Kurzlinks laufen innerhalb der angegebenen Zeit ab
  • einmal – einmalige Kurzlinks laufen innerhalb der angegebenen Zeit ab und werden automatisch gelöscht läuft nach dem Zugriff ab
  • Permanent – ​​ein langfristiger Kurzlink läuft nicht automatisch ab und akzeptiert nur manuelles Löschen

Nach der Generierung von urlKey wird er verglichen mit type werden in Strings umgewandelt und in Redis gespeichert, und der gespleißte Kurzlink wird ausgegeben.

③ Erhalten Sie den Kurzlink und schließen Sie die Zielumleitung ab

async getUrl(k: string) {
    const dataStr = await this.client.get(k);
    if (!dataStr) return;
    const { url, type, urlID } = JSON.parse(dataStr);
    if (type === &#39;once&#39;) {
        await this.client.del(k);
    }
    this.myLogger.log(`getUrl**${urlID}`, &#39;getUrl&#39;, false);
    return url;
}

Die Benutzerseite erhält ein ähnliches Bild wie http://localhost:8000/s/ku6a Code> Nach dem Klicken auf den Link entspricht dies dem Senden einer GET-Anfrage an den Kurzlink-Dienst. <p><strong>Nach Erhalt der Anfrage ruft der Dienst den Wert des Schlüsselfelds im Link ab, bei dem es sich um die Zeichenfolge <code>ku6a handelt, und verwendet ihn, um die Zuordnungsbeziehung in Redis zu finden.

Hier gibt es zwei Zweige: Der Dienst geht davon aus, dass der Kurzlink abgelaufen ist, und kehrt direkt zurück, da getUrl einen Nullwert und den Umleitungsdekorator zurückgibt leitet diese Anfrage an den Standardziellink weiter. 🎜🎜Wenn der relevante Wert erfolgreich in Redis gefunden wird, werden die Felder url und type gelesen. Wenn der Typ einmal ist, bedeutet dies, dass es sich um einen einmaligen Link handelt Die Löschmethode wird aktiv ausgelöst und der Ziellink wird schließlich zurückgegeben. 🎜🎜Zusätzliche Funktionen🎜🎜Verwenden Sie das Protokollsystem zur Ausgabe von Berichten🎜🎜Bei der Verwendung von Kurzlinks besteht eine hohe Wahrscheinlichkeit, dass relevante Datenstatistiken benötigt werden, ohne eine Datenbank zu verwenden. 🎜🎜Mit diesem Service können wir den Bericht über den Kurzlink-Zugriff noch am selben Tag ausfüllen, indem wir die Landeprotokolldateien scannen. 🎜🎜Fügen Sie das Feld 🎜urlID🎜 hinzu, wenn Sie Kurzlinks zur statistischen Differenzierung generieren und Protokolle aktiv ausgeben, wie folgt: 🎜
async createUrl(url: string, type: string = &#39;normal&#39;) {
    const urlKey = await this.handleUrlKey();
    const urlID = UUID.genV4().toString();
    const dataStr = JSON.stringify({
        urlID,
        url,
        type
    });
    this.myLogger.log(`createUrl**${urlID}`, &#39;createUrl&#39;, false);
    await this.client.set(urlKey, dataStr, type === &#39;permanent&#39; ? -1 : 300);
    return `${Config.defaultHost}/${urlKey}`;
}

然后在用户点击短链接时获取该短链接的urlID字段,并主动输出日志,如下:

async getUrl(k: string) {
    const dataStr = await this.client.get(k);
    if (!dataStr) return;
    const { url, type, urlID } = JSON.parse(dataStr);
    if (type === &#39;once&#39;) {
        await this.client.del(k);
    }
    this.myLogger.log(`getUrl**${urlID}`, &#39;getUrl&#39;, false);
    return url;
}

这么一来我们将能够在服务的logs目录中获得类似这样的日志:

2021-04-25 22:31:03.306	INFO	[11999]	[-]	createUrl**3f577625-474a-4e30-9933-e469ce3b0dcf
2021-04-25 22:31:38.323	INFO	[11999]	[-]	getUrl**3f577625-474a-4e30-9933-e469ce3b0dcf
2021-04-25 22:31:39.399	INFO	[11999]	[-]	getUrl**3f577625-474a-4e30-9933-e469ce3b0dcf
2021-04-25 22:31:40.281	INFO	[11999]	[-]	getUrl**3f577625-474a-4e30-9933-e469ce3b0dcf
2021-04-25 22:31:40.997	INFO	[11999]	[-]	getUrl**3f577625-474a-4e30-9933-e469ce3b0dcf
2021-04-25 22:31:41.977	INFO	[11999]	[-]	getUrl**3f577625-474a-4e30-9933-e469ce3b0dcf
2021-04-25 22:31:42.870	INFO	[11999]	[-]	getUrl**3f577625-474a-4e30-9933-e469ce3b0dcf
2021-04-25 22:31:43.716	INFO	[11999]	[-]	getUrl**3f577625-474a-4e30-9933-e469ce3b0dcf
2021-04-25 22:31:44.614	INFO	[11999]	[-]	getUrl**3f577625-474a-4e30-9933-e469ce3b0dcf

之后我们只需要以createUrl的日志为索引,对getUrl类型的日志进行计数,即可完成链接与点击数的报表,如果还需要其他维度的报表只需要在输出日志的时候带上即可,或者修改日志中间件中的日志范式。

使用方式

根据上述的流程,笔者写了一个比较简易的短链服务,大家可以开箱即用。

shorturl(欢迎大家Star⭐️⭐️)

具体启动方式

首先请确保有可用的redis,否则无法顺利启动服务。

git clone https://github.com/mykurisu/shorturl.git

cd shorturl

npm install

npm start

可用配置修改

与短链相关的配置收束在根目录的config.ts中。

serverConfig: {
    port: 8000,
},
redis: {
    port: 6379,
    host: &#39;0.0.0.0&#39;,
    db: 0,
},
cacheType: &#39;redis&#39;,
defaultHost: &#39;http://localhost:8000/s&#39;,
defaultIndex: &#39;http://localhost:8000/defaultIndex&#39;,
配置 默认值 配置用途
serverConfig.port 8000 服务启动端口
redis.port 6379 redis端口
redis.host 0.0.0.0 redis服务地址
redis.db 0 redis具体储存库表
cacheType redis 短链储存模式,接受memory/redis
maxRetryTimes 5 生成短链接最大重试次数
defaultHost http://localhost:8000/s 短链接前缀
defaultIndex http://localhost:8000/defaultIndex 短链接失效后重定向地址

内置接口

接口路由 请求方式 接口参数 接口用途
/s/createUrl POST url: string, type?: string 短链接生成接口
/s/deleteUrl POST k: string 删除短链接接口
/s/:key GET none 目标链接获取

拓展

① 储存降级策略

shorturl是有本地储存方案的,也就是说我们是可以监听Redis的状态,如果断开连接时就临时将数据储存到内存中,以达到服务降级的目的。当然我们也可以直接使用内存来储存短链内容,在config.ts配置中可以进行更改。

② 不仅仅是短链接服务

让我们脱离短链接这个束缚,其实shorturl本身已经是一个微型存储服务了,我们完全可以进行二次开发,输出更多的模块以支撑更多样的业务。

小结

整个短链接服务其实非常简单,麻烦的是服务的搭建,也就是迈出的第一步。笔者也是在无数次最初一步中挣扎,最终积累了fast-nest这么一个脚手架,希望能帮助到有同样境遇的同学。

另外,附上本文的服务源码 -- shorturl(欢迎大家Star)

更多编程相关知识,请访问:编程教学!!

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des von Nodejs+Nest implementierten Kurzlink-Dienstes. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.cn. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen