本篇文章為大家介紹一下基於Node框架Nest實作短連結服務的方法。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。
推薦學習:《nodejs 教學》
日常生活中能見到各種奇怪的短鏈接,每次點擊跳轉的時候,筆者都會覺得神奇,這短鍊是怎麼引導使用者到正確頁面的呢?
短鏈的原理就是以短博長,那麼這個短的字串怎麼能變成一長串連結呢?難道是靠某些神奇的加密演算法?並不是,我們只需要依賴key/value的映射關係就能輕鬆實現這個看似神奇的以短博長。
用一張圖,大家就能清晰的看到我們造訪短鏈的整個過程了。
首先,我們會有一個長鏈接,透過短鏈服務的處理,通常會輸出一個只有一層目錄的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
中,等待短連結產生然後輸出。
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。
在進行映射之前,我們需要對其進行唯一性判斷,雖然出現的可能性不大,但是還是需要防範短鏈覆蓋這類的問題。本服務的解決方案是重試生成,如果短鏈值不幸重複時將會進入重試分支,服務將內建可重試次數,如果重試的次數超過配置的字數,本次轉換將會回傳失敗。
除了url
,createUrl
方法也接受一個type
字段,這裡涉及特殊短鏈的特性。我們短鏈有三種模式:
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請求。
ku6a這個字串,利用它來找出Redis中的對應關係。
getUrl傳回了空值,重定向裝飾器會將本次請求重定向到預設的目標連結。
url和
type字段,如果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
类型的日志进行计数,即可完成链接与点击数的报表,如果还需要其他维度的报表只需要在输出日志的时候带上即可,或者修改日志中间件中的日志范式。
根据上述的流程,笔者写了一个比较简易的短链服务,大家可以开箱即用。
具体启动方式
首先请确保有可用的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.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中文網其他相關文章!