NestJS实战之开发短链服务(一)

前言

本文将会带领大家从0到1完成开发一个短链服务,因此,在这个专题的开头我们先做一些理论基础的铺垫。本系列文章不是标题党,因此不会讲一些空洞的大话、套话,我需要做的是脚踏实地的向各位读者传递有用的知识。

在阅读本文之前,希望你已经完全掌握NestJS的知识点,如果你是想学习NestJS的话,这篇专栏的文章可能不太适合你,建议你可以先查阅我另一篇专栏所著系列文章。👉NestJS - HsuYang的专栏 - 掘金 (juejin.cn)

好了,说完了题外话,我们就开始进入正题,各位同学抓稳扶牢,即将开始我们短链服务的开发历程。

什么是短链服务?

所谓短链,就是一个很短的域名,然后后面跟一串你看不懂,但是对于系统来说却有意义的标识码,比如,这就是抖音短视频的一个短链:v.douyin.com/ijp8qWLE 。其中,v.douyin.com(老实说,我觉得这个域名已经一点儿都不短了,😄)就是它的域名,ijp8qWLE就是这个所谓的有意义的标识码。

当我们访问服务的时候,如果服务器拿到这个有意义的标识码,在数据库能查到对应关联的最终跳转地址,此刻,服务端返回一个状态码为302的重定向码(为什么是302而不是301?因为如果是301是永久重定向,搜索引擎在解析地址的时候,搜索引擎后续再访问的时候,不会再解析短链的地址,而是定位到短链最终跳转的地址,我们肯定希望搜索引擎每次都要解析我们的短链地址而不是直接导向到最终的真实地址,所以必须要使用302的重定向状态码)。这个重定向发生在服务端,客户端是感觉不到的,并且重定向的地址具备可编程性(划重点!!!),这就让我们的工作变得大有可为,可以毫不夸张的说,一个公司想要做好跨端的全栈架构,那么就一定会构建自己的短链服务。

短链服务的原理真的非常简单,往大了说,就是一个简单302跳转,不过这里面还是有一些学问的,后面的文章我们就结合短链服务详细展开。

短链服务的用途

短链服务的用途在实际的生产开发中用途非常广泛,我根据我的理解 ,列举它的优点如下:

  • 简短,方便记忆;对于这个点来说,大家都深有体会,我们收到某些App的广告短信的时候,让你点开某个地址薅羊毛,这种场景下就适合推送短链,我们暂且不说如果你直接把原链接放到短信是否会增加计费的问题,就光是很长的地址,你的用户看到了估计心就已经拔凉拔凉的了,那么你投放的广告还有什么转化率呢?花钱赚吆喝嘛,哈哈。
  • 防封;这一点,可能有些做增长业务的同学有体会。比如你许久不联系的朋友突然给你发条消息,让你砍它一刀,这种一般都是短链地址,因为一旦被微信判定为恶意推广,就有可能被封禁的风险(如果直接把你的域名给干了,那就完犊子了,不过一般南山必胜客不会做的这么绝,哈哈哈),一旦被封禁一个短链,我们可以启用新的短链,对于我们原本的服务来说,就好比套上了一双白手套,不用亲自下场去干劣迹斑斑的活儿了,安全。
  • 跨平台,作多端拉齐网关;前面两个优点其实不是短链最大的优点,因为它还没有上升到跨平台架构的高度。现在,我们回想一些实际生活中的场景,在某些支付的场景下,我们扫码的支付的时候不管是微信还是支付宝都可以完成支付;另外一个场景,当我们在点餐的时候,桌上张贴的二维码,我们用美团app扫可以打开,用大众点评也可以打开,甚至可能用美团的微信小程序也可以打开,大家有没有想过这是怎么做到的,这就是短链服务做到的,当用我们的客户端访问短链服务的时候,短链服务会根据我们的UA信息,回吐我们当前客户端感兴趣的内容,因此,同一个二维码可以被多端唤起对应的app服务,这对于运营的投放和推广具有十分重要的意义。

开始设计

首先,我们先考虑一下我们要实现的内容,以及要使用的技术栈。短链服务的核心其实就一张表,就是用来存储标识码和真实地址之间的映射关系。

但是,为了使得我们的服务具有较大的扩展性(而不是直接耦合在业务代码中),我在设计的过程中,增加了一个叫做策略的概念,所谓策略的核心就是,一个函数,我传入给你的参数是Expressrequest对象,你返回给我的必须是一个有效的URL对象(为什么要用URL对象呢,因为使用它可以对url进行统一的描述,便于编程。),那么,我们在上一节中提到的内容就可以被描述成一个一个定制的策略,系统根据我们项目的需要,我们开发者事先编写这些策略,当需要某个策略的时候,我们只需要关联某个对应的策略即可。因此,我们把这些策略让用户配置,然后保存在数据库中,当需要的时候,使用JS的eval函数解析它们,完成对应的功能。

对于数据库,我们就使用MySQL即可,服务端技术,使用NestJS,我们肯定不会直接刀耕火种的操作数据库,因此,我们需要使用TypeORM,因为对短链的增删改查需要用到前端页面进行管理,我们就拟定使用Vue+ElementUI(具体是Vue2还是Vue3看你自己的喜好,短链的增删改查核心就2个页面,也扯不上什么可维护性什么高深的东西,怎么方便就可以怎么来),因为我们需要向数据库中写自定义的函数,所以需要用到代码编辑器,我们就使用微软开源的较为流行的MonacoEditor即可。

表结构设计

1、短链规则表

CREATE TABLE `rule` (
  `id` int NOT NULL AUTO_INCREMENT,
  `code` varchar(15) COLLATE utf8mb4_general_ci NOT NULL COMMENT '唯一标识',
  `description` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '描述',
  `target_url` varchar(8095) COLLATE utf8mb4_general_ci NOT NULL COMMENT '目标地址',
  `strategy_ids` varchar(1023) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '策略id数组,json格式',
  `custom_strategy_func` text COLLATE utf8mb4_general_ci COMMENT '自定义策略函数体',
  `is_valid` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否生效',
  `created_by` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '创建者',
  `updated_by` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '更新者',
  `created_at` datetime DEFAULT NULL COMMENT '创建时间',
  `updated_at` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

向大家介绍一下短链规则表中几个重要的字段,code字段用来存储短链码;target_url字段用来存储目标地址,这主要针对我们仅仅简单需要对原始地址瘦身的场景,如果复杂的场景可以不用填写这个字段的内容;strategy_ids主要用来存储关联的策略信息,custom_strategy_func字段跟策略类似,只不过它是一次性使用的策略,其它字段就不再赘述了,大家可以描述信息就知道它的用途了。

2、自定义策略表

CREATE TABLE `strategy` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `key` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '唯一标识 uuid',
  `name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '名称',
  `description` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '描述',
  `func` text COLLATE utf8mb4_general_ci NOT NULL COMMENT '策略函数体',
  `is_valid` tinyint(1) NOT NULL COMMENT '是否生效',
  `created_by` varchar(63) COLLATE utf8mb4_general_ci NOT NULL COMMENT '创建者',
  `updated_by` varchar(63) COLLATE utf8mb4_general_ci NOT NULL COMMENT '更新者',
  `created_at` datetime DEFAULT NULL COMMENT '创建时间',
  `updated_at` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_key` (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

接着我们也向大家介绍一下策略表中重要的字段的,key字段用来区分策略;func用来存用户保存的策略函数的内容。

因为我们需要使用typeorm来操作数据库,因此,我们对上述两张表生成对应的实体类。

1、短链规则类:

import {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
} from 'typeorm';

@Entity()
export class Rule {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  code: string;

  @Column()
  description: string;

  @Column({ name: 'target_url' })
  targetUrl: string;

  @Column({
    type: 'varchar',
    name: 'strategy_ids',
    transformer: {
      to(value: number[]): string {
        return !Array.isArray(value) ||
          (Array.isArray(value) && value.length === 0)
          ? ''
          : JSON.stringify(value);
      },
      from(value: string): number[] {
        return value === '' ? [] : JSON.parse(value);
      },
    },
  })
  strategyIds: number[];

  @Column({ name: 'custom_strategy_func', type: 'text' })
  customStrategyFunc: string;

  @Column({
    default: false,
    name: 'is_valid',
  })
  isValid: boolean;

  @Column({ name: 'created_by' })
  createdBy: string;

  @Column({ name: 'updated_by' })
  updatedBy: string;

  @CreateDateColumn({
    name: 'created_at',
  })
  createdAt: Date;

  @UpdateDateColumn({
    name: 'updated_at',
  })
  updatedAt: Date;
}

2、策略类

 
import {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
} from 'typeorm';

@Entity()
export class Strategy {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  key: string;

  @Column()
  name: string;

  @Column()
  description: string;

  @Column({
    type: 'text',
  })
  func: string;

  @Column({
    default: false,
    name: 'is_valid',
  })
  isValid: boolean;

  @Column({ name: 'created_by' })
  createdBy: string;

  @Column({ name: 'updated_by' })
  updatedBy: string;

  @CreateDateColumn({ name: 'created_at' })
  createdAt: Date;

  @UpdateDateColumn({ name: 'updated_at' })
  updatedAt: Date;
}

 

结尾

本文主要向大家阐述一些原理性的东西,在本文我们主要先讲清楚短链的理论性的东西以及完成数据库表结构的设计,后续开始阐述细节代码的开发。

下节更精彩,敬请期待......

原文转自:https://juejin.cn/post/7380221367823646729

  • 26
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值