Skip to content

使用NanoID替换整型ID

背景介绍

接口使用自增长整型作为唯一ID,数据和缓存查询都是用ID获取是常规方案。随着公司业务的发展,少数不法分子通过爬虫抓取接口数据,作为非法盈利之用。本司主营业务是长视频播放服务,存储和CND费用更加昂贵。其中一种爬取方案是,自增长ID轮询接口数据,所以此文的目的就是把所有暴露出来的资源ID都替换成随机字符串。

诚然,此方案防爬效果有限。须配合多种方案,验签、加密、限流、用户行为记录、CND加密、二次校验,这些不在此文讨论范围。

具体方案

网站主要涉及到电影剧集短视频,片单,文章资讯,复杂度在数据不仅要落库,还需要处理现有的缓存数据。

一.电影剧集ID

1.增加映射表 cms_content_id_mapping

sql
CREATE TABLE `cms_content_id_mapping` (
  `id` varchar(25) NOT NULL COMMENT 'id',
  `category` TINYINT(4) NOT NULL COMMENT '内容类型,0,电影,1剧集,2短视频',
  `mapping_id` varchar(25) NOT NULL COMMENT '映射ID',
  PRIMARY KEY (`id`, `category`) USING BTREE,
  KEY `idx_mapping_id` (`mapping_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='资源ID映射表';

2.增加双向缓存

原缓存不动 使用hash存储mappingId和contentId的双向关系,并且可以批量获取 详情见 groot.cms.cache.ContentMappingCache

3.获取电影剧集详情接口修改如下

java
if (StringUtils.isNumeric(id)) {
    // 增加配置开关,暂时保留旧的ID
    if (!websiteMappingConfig.getOldIdIsOpen()){
        throw new RequestParameterException();
    }
} else {
    id = contentMappingCache.getContentIdCacheByMappingId(id, category);
}

二.片单ID

1.增加字段 mapping_id

sql
alter table cms_album add column `mapping_id` varchar(25) NOT NULL COMMENT '映射ID' after id;

2.新增索引

sql
alter table cms_album add index idx_mapping_id(mapping_id) USING BTREE;

3.新增缓存

4.片单缓存增加字段mappingId

三.文章资讯ID

文章资讯不需要处理缓存数据

1.新增字段 mapping_id

sql
alter table cms_news add column `mapping_id` varchar(25) NOT NULL COMMENT '映射ID' after sort;

2.新增索引

sql
alter table cms_news add index idx_mapping_id(mapping_id) USING BTREE;

四.数据和缓存初始化

java
public void initData(){
    StopWatch stopWatch = new StopWatch();

    // contentMappingCache
    for (ContentCategoryEnum categoryEnum : ContentCategoryEnum.values()) {
        stopWatch.start(categoryEnum.getDesc() + "初始化 ");
        initMovieMapping(categoryEnum);
        stopWatch.stop();
    }

    // alumCache
    stopWatch.start("片单初始化");
    initAlbumMapping();
    stopWatch.stop();

    // cmsNews
    stopWatch.start("新闻资讯初始化");
    initNewsMapping();
    stopWatch.stop();

    log.info(stopWatch.prettyPrint());
}

五.修改原来的sitemap.xml相关接口

修改原有ID生成逻辑,其他保持不变

六.映射ID生成逻辑

鉴于UUID长度太长,这里的mappingId是用NanoId。 修改默认字符集为“0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ”,去除默认的“_-”,防止和URL中的字符冲突,长度使用默认的21位 具体代码如下:

java
public class NanoIdUtil {
    public static final SecureRandom DEFAULT_NUMBER_GENERATOR = new SecureRandom();

    /**
     * The default alphabet used by this class.
     * Creates url-friendly NanoId Strings using 64 unique symbols.
     */
    public static final char[] DEFAULT_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();

    /**
     * The default size used by this class.
     * Creates NanoId Strings with slightly more unique values than UUID v4.
     */
    public static final int DEFAULT_SIZE = 21;

    public static String randomNanoId(){
        return NanoIdUtils.randomNanoId(DEFAULT_NUMBER_GENERATOR, DEFAULT_ALPHABET, DEFAULT_SIZE);
    }
}

使用方法如下:

java
public static void main(String[] args) {
    System.out.println(NanoIdUtil.randomNanoId());
}

Maven 坐标:

<dependency>
  <groupId>com.aventrix.jnanoid</groupId>
  <artifactId>jnanoid</artifactId>
  <version>2.0.0</version>
</dependency>

修改后的网站url效果如下

java
http://xxxxxx.com/detail/movie/76Y3TWpZDR8aOhbd19cyT-Double-Dad
http://xxxxxx.com/collection/QXUGQIYQcYKM1jDSwY83G-afdfadggd?name=qins

七.参考资料:

Power by vitepress