>  기사  >  웹 프론트엔드  >  Nodejs+Nest에서 구현한 단축링크 서비스에 대한 자세한 설명

Nodejs+Nest에서 구현한 단축링크 서비스에 대한 자세한 설명

青灯夜游
青灯夜游앞으로
2021-04-30 10:48:022793검색

이 글에서는 Node 프레임워크 Nest를 기반으로 단축 링크 서비스를 구현하는 방법을 소개합니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.

Nodejs+Nest에서 구현한 단축링크 서비스에 대한 자세한 설명

추천 학습: "nodejs tutorial"

우리는 클릭하여 점프할 때마다 온갖 종류의 이상한 짧은 링크를 볼 수 있습니다. 저자는 이 짧은 링크가 사용자를 어떻게 연결하는지 대단하다고 느낄 것입니다. 어느 쪽이 올바른 페이지로 연결되나요?

짧은 링크의 원리

짧은 링크의 원리는 짧은 링크를 길게 만드는 것인데 어떻게 이 짧은 문자열을 긴 링크의 문자열로 바꿀 수 있을까요? 마법의 암호화 알고리즘에 의존하고 있습니까? 아니요, 겉보기에 마법처럼 보이는 이 일을 쉽게 달성하려면 키/값 매핑 관계에만 의존하면 됩니다. 단기적으로 자세히 알아보세요.

사진을 통해 누구나 짧은 링크에 접속하는 전 과정을 명확하게 볼 수 있습니다.

Nodejs+Nest에서 구현한 단축링크 서비스에 대한 자세한 설명

먼저 짧은 링크 서비스 처리를 통해 일반적으로 디렉토리가 한 개만 있는 URL이 출력되고, 얻은 URL을 배포할 수 있습니다.

그러면 사용자가 짧은 링크를 클릭한 후 가장 먼저 도달하는 것은 대상 페이지가 아니라 짧은 링크 서비스입니다.

짧은 링크 서비스는 링크의 경로 이름을 가로채서 이를 매핑 관계에서 해당 값을 찾는 키로 사용합니다.

해당 값을 찾을 수 없으면 짧은 링크가 존재하지 않거나 만료되었음을 의미합니다. 쿼리에 성공하면 짧은 링크 서비스는 해당 값의 대상 링크로 직접 302하여 짧은 링크 액세스를 완료합니다.

특정 구현

재료: Fast-NestScaffolding, Redis

전체 구현은 3개 부분으로 나뉩니다.

1긴 링크 수신

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

서비스에서 createUrl만들기 >인터페이스에서 urltype 필드를 수신하여 shorturlService에 전달하고 짧은 링크가 생성될 때까지 기다린 후 출력합니다. createUrl接口,接收url已经type字段,并将其传入shorturlService中,等待短链接生成然后输出。

② 生成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;
}

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

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

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

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

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

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

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

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

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

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

如果在Redis中顺利查到相关的值,则会读取其中的urltype

② shortKey 생성
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}`;
}

먼저 Math.random().toString(36).slice(-4)를 통해 4자리 임의의 문자열을 가져옵니다. > , 이는 짧은 링크의 경로 이름으로 사용됩니다.

매핑하기 전에 고유성을 판단해야 합니다. 그럴 가능성은 없지만 짧은 체인 커버리지와 같은 문제에 대해서는 여전히 경계해야 합니다. 이 서비스의 해결책은 재시도 생성입니다. 불행하게도 짧은 체인 값이 반복되면 서비스에는 재시도 횟수가 구성된 단어 수를 초과하는 경우 재시도 분기가 적용됩니다. 이 변환은 실패를 반환합니다.

url 외에도 createUrl 메소드는 특수 짧은 링크의 특성과 관련된 type 필드도 허용합니다. 짧은 링크에는 세 가지 모드가 있습니다.

  • 일반 - 일반 짧은 링크는 지정된 시간 내에 만료됩니다.
  • 한 번 - 일회성 짧은 링크는 지정된 시간 내에 만료되며 자동으로 만료됩니다. 액세스 후 만료
  • 영구 - 장기 짧은 링크는 자동으로 만료되지 않으며 수동 삭제만 허용됩니다.

urlKey를 생성한 후 비교됩니다. type이 있는 문자열을 문자열로 변환하여 redis에 저장하고, 이어붙인 짧은 링크가 출력됩니다.

3 짧은 링크를 수신하고 대상 리디렉션을 완료합니다

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;
}
사용자 측에서는 http://localhost:8000/s/ku6a와 유사한 메시지를 받게 됩니다. code> 링크를 클릭한 후 짧은 링크 서비스에 GET 요청을 보내는 것과 같습니다.

요청을 받은 후 서비스는 링크의 키 필드 값(ku6a 문자열)을 획득하고 이를 사용하여 Redis에서 매핑 관계를 찾습니다. 🎜🎜여기에는 두 가지 분기가 있습니다. 하나는 Redis에서 관련 값을 쿼리할 수 없다는 것입니다. getUrl이 null 값과 리디렉션 데코레이터를 반환하기 때문에 서비스는 짧은 링크가 만료되었다고 생각하고 직접 반환합니다. 이 요청을 기본 대상 링크로 리디렉션합니다. 🎜🎜Redis에서 해당 값을 성공적으로 찾으면 urltype 필드를 읽습니다. type이 한 번이면 일회성 링크라는 의미입니다. . 삭제 방법이 활성화되고 대상 링크가 결국 반환됩니다. 🎜🎜추가 기능🎜🎜로그 시스템을 사용하여 보고서 출력🎜🎜짧은 링크를 사용할 때 관련 데이터 통계가 필요할 가능성이 높습니다. 데이터베이스를 사용하지 않고 데이터 통계를 수행하는 방법은 무엇입니까? 🎜🎜이 서비스에서는 착륙 로그 파일을 스캔하여 당일에 짧은 링크 액세스 보고서를 완료할 수 있습니다. 🎜🎜통계적 차별화를 위해 짧은 링크를 생성하고 적극적으로 로그를 출력할 때 다음과 같이 🎜urlID🎜 필드를 추가하세요. 🎜
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)

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

위 내용은 Nodejs+Nest에서 구현한 단축링크 서비스에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제