Home  >  Article  >  Web Front-end  >  Detailed explanation of the short link service implemented by Nodejs+Nest

Detailed explanation of the short link service implemented by Nodejs+Nest

青灯夜游
青灯夜游forward
2021-04-30 10:48:022815browse

This article will introduce to you the method of implementing short link service based on the Node framework Nest. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to everyone.

Detailed explanation of the short link service implemented by Nodejs+Nest

Recommended study: "nodejs tutorial"

We can see all kinds of strange short links in our daily life. Every time I click to jump, I feel magical. How does this short link guide users to the correct page?

Principle of short chain

The principle of short chain is to make a short blog longer, so how can this short string be turned into a long string of links? Is it relying on some magical encryption algorithm? No, we only need to rely on the key/value mapping relationship to easily achieve this seemingly magical making short work long.

With a picture, everyone can clearly see the entire process of accessing the short link.

Detailed explanation of the short link service implemented by Nodejs+Nest

First, we will have a long link. Through the processing of the short link service, a URL with only one layer of directories will usually be output. Then we can process the obtained URL. distribution.

Then we get to the user side. After the user clicks on the short link, the first thing they reach is not the target page, but the short link service.

The short link service will intercept the pathname on the link and use it as a key to find the corresponding value in the mapping relationship.

If the corresponding value cannot be found, it means that the short link does not exist or has expired; if the query is successful, the short link service will directly 302 to the target link in the value to complete a short link access. .

Specific implementation

Materials: Fast-NestScaffolding, Redis

The entire implementation is split into 3 parts:

① Receive long link

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

Create a createUrl interface in the service, receive the url and type fields, and add It is passed into shorturlService, waits for the short link to be generated and then outputs it.

② Generate shortKey

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;
}

First get a 4-digit random string through Math.random().toString(36).slice(-4), this will Pathname as a short link.

Before mapping, we need to judge its uniqueness. Although it is unlikely, we still need to prevent problems such as short chain coverage. The solution of this service is to retry generation. If the short chain value is unfortunately repeated, it will enter the retry branch. The service will have a built-in number of retries. If the number of retries exceeds the configured number of words, this conversion will return failure. .

In addition to url, the createUrl method also accepts a type field, which involves the characteristics of special short links. Our short links have three modes:

  • normal - normal short links will expire within the specified time
  • once - one-time short links will expire within the specified time, It will automatically expire after being accessed
  • permanent - long-term short link will not automatically expire and only accepts manual deletion

After generating urlKey, it will be the same as type is converted into a string and stored in redis, and the spliced ​​short link is output.

③ Receive the short link and complete the target redirection

@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;
}

The user side will get a link similar to http://localhost:8000/s/ku6a, after clicking It is equivalent to sending a GET request to the short link service.

After receiving the request, the service obtains the value of the key field in the link, which is the string ku6a, and uses it to find the mapping relationship in Redis.

There are two branches here. One is that the relevant value cannot be queried in Redis. The service thinks that the short link has expired and will return directly because getUrl returns a null value and redirects. The decorator will redirect this request to the default target link.

If the relevant value is successfully found in Redis, the url and type fields will be read. If type is once, it means that this is a one-time use. The link will actively trigger the deletion method and eventually return the target link.

Extra functions

Use the log system to output reports

When using short links, there is a high probability that relevant data statistics will be needed. How to collect data without using a database? What about statistics?

In this service, we can complete the report of short-link access on the same day by scanning the landing log file.

When generating short links, add the urlID field for statistical differentiation and actively output logs, as follows:

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)

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

The above is the detailed content of Detailed explanation of the short link service implemented by Nodejs+Nest. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:juejin.cn. If there is any infringement, please contact admin@php.cn delete