您好,欢迎访问一九零五行业门户网

详解Nodejs+Nest实现的短链接服务

本篇文章给大家介绍一下基于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中,等待短链接生成然后输出。
② 生成shortkeyasync 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字段,这里涉及特殊短链的特性。我们短链有三种模式:
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.geturlasync 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中顺利查到相关的值,则会读取其中的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-e469ce3b0dcf2021-04-25 22:31:38.323 info [11999] [-] geturl**3f577625-474a-4e30-9933-e469ce3b0dcf2021-04-25 22:31:39.399 info [11999] [-] geturl**3f577625-474a-4e30-9933-e469ce3b0dcf2021-04-25 22:31:40.281 info [11999] [-] geturl**3f577625-474a-4e30-9933-e469ce3b0dcf2021-04-25 22:31:40.997 info [11999] [-] geturl**3f577625-474a-4e30-9933-e469ce3b0dcf2021-04-25 22:31:41.977 info [11999] [-] geturl**3f577625-474a-4e30-9933-e469ce3b0dcf2021-04-25 22:31:42.870 info [11999] [-] geturl**3f577625-474a-4e30-9933-e469ce3b0dcf2021-04-25 22:31:43.716 info [11999] [-] geturl**3f577625-474a-4e30-9933-e469ce3b0dcf2021-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.gitcd shorturlnpm installnpm 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实现的短链接服务的详细内容。
其它类似信息

推荐信息