中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Nodejs+Nest如何實現的短鏈接服務

發布時間:2021-04-30 11:10:29 來源:億速云 閱讀:229 作者:小新 欄目:web開發

小編給大家分享一下Nodejs+Nest如何實現的短鏈接服務,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

日常生活中能見到各種奇怪的短鏈接,每次點擊跳轉的時候,筆者都會覺得神奇,這短鏈是怎么將用戶引導到正確頁面的呢?

短鏈原理

短鏈的原理就是以短博長,那么這個短的字符串怎么才能變成一長串鏈接呢?難道是靠某些神奇的加密算法?并不是,我們只需要依賴key/value的映射關系就能輕松實現這個看似神奇的以短博長

用一張圖,大家就能清晰的看到我們訪問短鏈的整個過程了。

Nodejs+Nest如何實現的短鏈接服務

首先,我們會有一個長鏈接,通過短鏈服務的處理,通常會輸出一個只有一層目錄的URL,然后我們可以將獲取的URL進行分發。

然后就到了用戶側,用戶點擊短鏈之后,先到達的并不是目標頁面,而是短鏈服務。

短鏈服務會截取鏈接上的pathname,并將其當做key,到映射關系中查找對應的value。

如果查到不到對應的value,則表示這個短鏈不存在或者已失效;如果查詢成功,則會由短鏈服務直接302到value中的目標鏈接,完成一次短鏈訪問。

具體實現

原料: Fast-Nest腳手架、Redis

整個實現分拆成3個部分:

① 接收長鏈接

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

在服務中創建一個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('超過重試次數,請重新生成鏈接', 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('/:key')
@Redirect(Config.defaultIndex, 302)
async getUrl(
        @Param('key') 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 === 'once') {
        await this.client.del(k);
    }
    return url;
}

用戶側會獲得一個類似http://localhost:8000/s/ku6a的鏈接,點擊之后相當于是給短鏈接服務發送了一個GET請求。

服務接收到請求之后獲取鏈接中key字段的值,也就是ku6a這個字符串,利用它查找Redis中的映射關系。

這里有兩個分支,一個是在Redis中無法查詢到相關的值,服務則認為短鏈接已經失效會直接return,因為getUrl返回了空值,重定向裝飾器會將本次請求重定向到默認的目標鏈接中。

如果在Redis中順利查到相關的值,則會讀取其中的urltype字段,如果type為once則代表這個是一次性鏈接,會主動觸發刪除方法,最終都會返回目標鏈接。

額外功能

利用日志系統輸出報表

使用短鏈接時,大概率都會需要相關的數據統計,怎么樣在不使用數據庫的前提下進行數據統計呢?

在本服務中,我們可以通過對落地日志文件的掃描,完成當日短鏈訪問的報表。

在生成短鏈接的時候加上urlID字段進行統計區分并主動輸出日志,如下:

async createUrl(url: string, type: string = 'normal') {
    const urlKey = await this.handleUrlKey();
    const urlID = UUID.genV4().toString();
    const dataStr = JSON.stringify({
        urlID,
        url,
        type
    });
    this.myLogger.log(`createUrl**${urlID}`, 'createUrl', false);
    await this.client.set(urlKey, dataStr, type === 'permanent' ? -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 === 'once') {
        await this.client.del(k);
    }
    this.myLogger.log(`getUrl**${urlID}`, 'getUrl', 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: '0.0.0.0',
    db: 0,
},
cacheType: 'redis',
defaultHost: 'http://localhost:8000/s',
defaultIndex: 'http://localhost:8000/defaultIndex',
配置默認值配置用途
serverConfig.port8000服務啟動端口
redis.port6379redis端口
redis.host0.0.0.0redis服務地址
redis.db0redis具體儲存庫表
cacheTyperedis短鏈儲存模式,接受memory/redis
maxRetryTimes5生成短鏈接最大重試次數
defaultHosthttp://localhost:8000/s短鏈接前綴
defaultIndexhttp://localhost:8000/defaultIndex短鏈接失效后重定向地址

內置接口

接口路由請求方式接口參數接口用途
/s/createUrlPOSTurl: string, type?: string短鏈接生成接口
/s/deleteUrlPOSTk: string刪除短鏈接接口
/s/:keyGETnone目標鏈接獲取

拓展

① 儲存降級策略

shorturl是有本地儲存方案的,也就是說我們是可以監聽Redis的狀態,如果斷開連接時就臨時將數據儲存到內存中,以達到服務降級的目的。當然我們也可以直接使用內存來儲存短鏈內容,在config.ts配置中可以進行更改。

② 不僅僅是短鏈接服務

讓我們脫離短鏈接這個束縛,其實shorturl本身已經是一個微型存儲服務了,我們完全可以進行二次開發,輸出更多的模塊以支撐更多樣的業務。

看完了這篇文章,相信你對“Nodejs+Nest如何實現的短鏈接服務”有了一定的了解,如果想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

永昌县| 永定县| 剑川县| 夏邑县| 周宁县| 靖江市| 鹿泉市| 平顶山市| 长汀县| 依安县| 湄潭县| 大石桥市| 遂溪县| 和静县| 杭锦旗| 邓州市| 大荔县| 明星| 上虞市| 泗水县| 夹江县| 资中县| 千阳县| 盐津县| 海南省| 平度市| 郎溪县| 固安县| 芷江| 内江市| 宜丰县| 延寿县| 高平市| 剑河县| 中牟县| 秦皇岛市| 巴楚县| 河池市| 曲周县| 岳阳市| 图片|