简介:一套基于PHP的短网址/短链接生成源码,采用黑色简洁风格,适合个人站长或开发者快速部署在线短链服务。前端支持创建自定义短链、密码保护、链接点击统计、暗色主题与书签工具,后端可管理网址、编辑站点设置、接入广告以及使用自定义CSS,整体功能完整,兼顾实用与二次开发便利性。压缩包共103个文件,约681KB,以PHP逻辑代码为主,辅以CSS、JavaScript构建前端交互,SCSS/LESS样式源码便于定制,另含SQL数据库脚本、HTML模板及字体资源。目前已有212人学习浏览,适合需要快速上线短链系统或研究PHP项目结构的初学者。通过这套代码可掌握短链接生成、参数加密、后台管理及广告位挂载的完整实现思路,代码量精简,易于本地部署和改造。
1. 黑色简洁的 PHP 短网址源码能干什么,值不值得花时间搭
一个黑色简洁的 PHP 短网址短链接生成源码包,解压开通常就是一个 index.php、一个 config.php、一个 static 样式目录和一张建表 SQL。核心逻辑不复杂:你在暗色表单里贴一条长链接,返回一个短码;别人访问这个短码,服务端查库后给你跳回原地址。它解决的是很多团队都有的需求——不想把短链数据存在第三方平台,又不想为这么点事单独引一套 Node 或 Go 服务。
个人站长可以拿它做一个工具站,运营团队可以内部用来生成活动链接。前提是你得清楚 PHP 短链的运行机制和部署位置。这篇按部署顺序,把原理、参数和常见的坑一次讲完。
2. 短链接是怎么变短的:重定向机制、短码算法与表结构
短链接表面上是“把 URL 变短”,本质是数据库里的一条映射记录。用户访问短地址时,服务端解析出短码、查表、拿到长链接、返回重定向响应。浏览器地址栏不会显示中间过程,但如果后端响应慢了,你会看到地址栏先闪一下短域名、再跳到目标域名的两段变化。
2.1 一次点击背后发生了什么:302 与 301 的选择
打开浏览器的开发者工具,切到 Network 面板,访问一个短链接,会看到两个请求:第一个请求短域名拿到 302(或 301),第二个请求才是长链接的目标地址。HTTP 状态码决定了这次跳转是否被客户端缓存。
// 跳转是短链源码最核心的一行 header('Location: ' . $longUrl, true, 302); exit;大多数这类源码默认用 302,原因是统计要准。301 会被浏览器、搜索引擎长时间缓存:同一个用户第二次点击时,浏览器可能直接跳到目标地址,根本不再请求你的服务器,hits 计数就会漏。如果做渠道追踪,建议保持 302;如果纯粹想给老链接一个永久迁移的出口并且不在乎点击数据,可以改 301。
注意 header() 调用之前不能有任何输出,哪怕是一个空格、一行 BOM,都会触发 “headers already sent” 警告。源码包里 index.php 如果第一行是<?php而没有空行,通常没问题;如果你用编辑器改过文件且带 BOM 保存,就会踩这个坑。
有些实现会在跳转前检查记录死活,短码存在但链接已失效时返回自定义 404 页面而不是让浏览器报错。这个判断要放在跳转之前:
if (!$row) { http_response_code(404); exit('短链接不存在或已失效'); }2.2 短码生成算法:自增 ID 转 62 进制与随机短码的取舍
短码怎么生成,是区分源码实现质量的地方。常见做法有两类。
第一类是自增 ID 转 62 进制。写入一条记录拿到自增 id,再把 id 转换成由数字、小写字母、大写字母组成的 62 进制字符串。好处是天然唯一、不用查重、短码长度可控,缺点是短码可预测,别人能顺着规律遍历到你所有的短链。
function encode62(int $id): string { $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $out = ''; while ($id > 0) { $out = $chars[$id % 62] . $out; $id = intdiv($id, 62); } return $out === '' ? '0' : $out; }这段函数的参数是自增 ID,返回值是短码。intdiv 是 PHP 7 之后的整数除法,兼容 PHP 8.x。注意字符集顺序:把数字排在前面,长度短的短码会以数字开头,Nginx 伪静态正则如果写得不严谨容易漏掉。更好的做法是把 26 个小写字母放前面,让短码永远以字母开头。这个函数只需要正方向转换,因为跳转时是按 short_code 字符串查库的,不需要把短码再解码回 ID,这就是它比 Base64 方案省事的地方。
短码长度估算:id 增长到 62^6 ≈ 568 亿的量级才需要第七位,对绝大多数站点来说 6 位短码够用几年。有的源码固定输出 6 位,不足的在前面补零或补随机字符,这种实现会让短码带上前导 0,配合正则时要留意。
第二类是随机短码,取 6~8 位随机字符。好处是不可预测、没法批量遍历,但每次都要查一次唯一索引,冲突后重试。源码里常见实现是把随机源打散再截取:
// 随机短码不能让 mt_rand 单独决定,字符集要打散 $seed = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $code = substr(str_shuffle($seed), 0, 6);用 str_shuffle 每次生成一个 62 位的乱序字符串再截取 6 位,比重复 mt_rand 取下标干净。它的坑在于:str_shuffle 的随机性依赖系统熵源,高并发下可能出现重复,所以入库前必须有 UNIQUE 约束并捕获插入失败重试,而不是先 SELECT 判断存在与否再去 INSERT。
2.3 表结构这样建:后续统计和清洗都省心
短链接服务的核心表通常只有一张。字段不必多,但该有的唯一索引和冗余字段不能省:
CREATE TABLE `short_urls` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT, `short_code` varchar(10) DEFAULT NULL COMMENT '短码,生成后回填', `long_url` text NOT NULL COMMENT '原始长链接', `hits` int unsigned NOT NULL DEFAULT 0 COMMENT '点击次数', `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `expire_at` datetime DEFAULT NULL COMMENT '过期时间,NULL为永久', PRIMARY KEY (`id`), UNIQUE KEY `uk_code` (`short_code`), KEY `idx_created` (`created_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;字段设置就三个重点:
- short_code 必须建唯一索引。自增 ID 转 62 进制虽然在业务上不会重复,但索引能兜住多进程环境下的异常写入;随机短码方案更是必须靠它捕获冲突。这里允许 NULL,是因为常见写入流程是先插入长链接拿自增 id、算短码、再回填,插入阶段短码还不存在,唯一索引对 NULL 不去重,正好不互相干扰。
- long_url 用 text 而不是 varchar(255)。很多营销链带有 UTM 参数,动辄二三百字符,varchar(255) 在设计上就限制死了。
- expire_at 允许为 NULL,表示永久链接。把过期和永久混成一个时间字段,会让判断逻辑多出一堆分支。
写入流程是:先插入 long_url 拿到自增 id,再计算短码,再 UPDATE 回 short_code。第一次插入时 short_code 为 NULL,因为这个短码依赖 id。另一类做法是先用业务规则生成一个不依赖 id 的短码,建表时直接写死 NOT NULL,适合随机短码方案。
3. 把 .rar 跑起来:环境准备、伪静态与最小可运行配置
拿到 .rar 先不要急着传服务器。先在本地用 PHP 内置服务器或一键面板跑通,生成一个短链接,确认跳转正常,再上生产。很多翻车现场都是跳过了本地验证,直接把目录扔到线上,然后对着 500 页面无从下手。
3.1 解压后先认清目录结构,别把整个包扔到根目录
这类源码包的目录结构通常是这样(具体文件名以你手里的压缩包为准):
shorturl/ ├── index.php # 入口:生成表单和跳转处理都在这 ├── config.php # 数据库、域名、盐值配置 ├── install.sql # 建表语句 ├── static/ │ ├── style.css # 黑色主题样式 │ └── script.js └── admin/ └── index.php # 后台管理(如果有)先说边界:源码里如果自带 .user.ini 或 .htaccess,说明作者考虑过运行目录问题。没有的话,让站点根目录指向哪儿,取决于入口文件在哪一层。
常见做法是让 Web 根目录指向源码外层目录。这时要小心:install.sql 和 config.php 如果放在根目录,用户直接访问http://域名/config.php虽然因为连不上库会报错,但会暴露源码结构。我一般会把站点根目录指向一个只放入口文件的子目录,把 config.php 放到上一级,用相对路径引用。集成环境的“运行目录”里可以直接配。
解压有个细节:.rar 在 Linux 服务器上用 unrar 命令解压,如果是中文文件名,加 -o+ 覆盖参数避免交互卡住:
unrar x -o+ shorturl.rar /var/www/解压完马上检查文件权限。PHP 需要读取目录和文件,但不需要给它整个目录的写权限。config.php 如果包含数据库密码,权限设 640 就够了,不要顺手 777。
3.2 Nginx 与 Apache 下的伪静态配置(含宝塔面板操作)
短链接跳转的本质是把/abcd123这样的路径交给 index.php 处理。不配伪静态也能跑,但 URL 会变成/index.php?code=abcd123,谈不上“短”。所以伪静态是必须的。
Nginx 下,server 块里加上:
location / { if (!-e $request_filename) { rewrite ^/([a-zA-Z0-9]+)/?$ /index.php?code=$1 last; } }关键参数是最后面的 last,它表示重写后重新进入 location 匹配,PHP 会被解析到。不要用 break,break 在内部重写后不会重新走 location,PHP-FPM 可能接收不到正确的 QUERY_STRING。
Apache 下对应的 .htaccess 写法:
RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^([a-zA-Z0-9]+)$ index.php?code=$1 [L]如果用的是宝塔面板,Nginx 伪静态直接在站点设置里选“ThinkPHP”或者自定义粘贴上面的规则。宝塔默认 PHP 是作为 FastCGI 跑的,规则放在 server 块的 location 里没有区别,只要确认 rewrite 的 target 是 index.php 而不是绝对路径 /index.php。一旦站点部署在子目录,绝对路径会把请求引回根目录。
注意:Nginx rewrite 的 target 写成 /index.php 还是 index.php,取决于站点根目录位置。站点根目录就是源码目录时用绝对路径没问题;跑在子目录时用相对路径更稳。
伪静态是短链服务 404 的头号来源。配好之后先用真实存在的短码测试,再用不存在的短码测试,后者应该落到“短链接不存在”的处理逻辑而不是 Nginx 的 404 页面。
3.3 数据库初始化和 config.php 参数核对
先创建数据库和账号,再导入 .sql:
mysql -uroot -p -e "CREATE DATABASE shorturl DEFAULT CHARACTER SET utf8mb4;" mysql -uroot -p shorturl < install.sql创建时显式指定 utf8mb4,避免建表后中文长链接在写入时报 “Incorrect string value”。再用SHOW CREATE TABLE short_urls确认表结构,重点看 short_code 的索引是否带 UNIQUE,很多网上下载的源码 SQL 里漏了索引。
config.php 需要核对的参数一般有这四个:
| 参数 | 常见值 | 说明 |
|---|---|---|
| DB_HOST | 127.0.0.1 | 不要用 localhost,容易触发 PHP mysqli 的 socket 连接分支 |
| DB_NAME | shorturl | 与建库时一致 |
| DB_USER / DB_PASS | 专用账号 | 别用 root 跑线上 |
| SITE_URL | https://s.example.com | 生成短链时拼接的前缀,必须以 / 结尾或由代码统一处理 |
我见过最多的问题是 SITE_URL 没带协议头,生成出来的短链是//s.example.com/abc,在部分 App 内嵌浏览器里解析异常。写协议头是基本修养。
本地验证时可以用 PHP 内置服务器,不用配 Nginx:
php -S 0.0.0.0:8080 -t /path/to/shorturl内置服务器不识别伪静态,所以访问/index.php?code=xxx是通的;能走通说明 PHP 逻辑没问题,再上 Nginx 就是纯配置的事。这一步能把“代码问题”和“配置问题”分开排查。
4. 关键代码读哪几个文件:路由入口、生成函数与 JSON API 改造
短链接源码的代码量不大,真正要懂的三个点:入口怎么跳转、短码怎么生成、接口怎么扩展。把这三点吃透,改成自己项目的内部工具就没障碍。
4.1 入口文件 index.php 的跳转逻辑
大多数这类源码是单入口,index.php 同时承担两件事:GET 请求不带参数时输出生成表单的 HTML;带 code 参数时执行跳转。核心跳转逻辑可以抽象成这样:
$code = $_GET['code'] ?? ''; if ($code !== '') { $stmt = $pdo->prepare('SELECT long_url, expire_at FROM short_urls WHERE short_code = ?'); $stmt->execute([$code]); $row = $stmt->fetch(PDO::FETCH_ASSOC); if ($row && ($row['expire_at'] === null || $row['expire_at'] > date('Y-m-d H:i:s'))) { header('Location: ' . $row['long_url'], true, 302); exit; } http_response_code(404); exit('短链接不存在或已过期'); } // 没有 code 参数就渲染生成表单这段代码有三个容易被忽略的细节。第一,long_url 从数据库取出来后不要再做 htmlspecialchars 处理,因为入库前已经过滤过一次,输出端再转义会把合法的 & 参数转坏。第二,expire_at 的判断要用“过期时间大于当前时间”,不能只判断非空。第三,PDO 的 prepare 是防 SQL 注入的底线,不要把 $code 直接拼进 SQL。
这里的 $pdo 是 config.php 里初始化的 PDO 实例。常见做法是把这四行初始化单独抽成一个 db.php:
// db.php $pdo = new PDO( 'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=utf8mb4', DB_USER, DB_PASS, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ] );PDO::ATTR_ERRMODE 设为 EXCEPTION,代码里就不需要到处写if (!$stmt)。错误会被统一抛成异常,调试时看异常信息比看 false 直观得多。
4.2 短码生成函数:62 进制转换与碰撞兜底
在 2.2 节讲过自增 ID 转 62 进制的原理,落到源码文件里,它通常是一个单独函数,叫 encode、shortCode 或 id2code。这里写一个带碰撞处理的完整版本:
function generateShortCode(PDO $pdo, int $id): string { $code = encode62($id); // 理论上自增ID转62进制不会碰撞,但多进程批量导入时可能有脏数据 $stmt = $pdo->prepare('SELECT COUNT(*) FROM short_urls WHERE short_code = ?'); $stmt->execute([$code]); if ((int)$stmt->fetchColumn() > 0) { $code = strrev($code); // 倒序 $code = strtoupper($code); // 再转大写,二次尝试 } return $code; }参数说明:$pdo 是为了在函数内做查重,$id 是上一步插入记录拿到的自增主键。这里用 strrev 和 strtoupper 做兜底是个取巧方案,保证不引入新的随机源;如果二次尝试仍然冲突,说明表数据已经有异常,需要人工看表。
真正生产级的做法是给 short_code 加唯一索引,插入时捕获 1062 冲突再换码重试。也就是反过来:先尝试插入带短码的记录,DUPLICATE KEY 就换一个码重试。相比先查再插,后者在低并发下够用,批量场景请用冲突重试。
4.3 加一个 JSON 接口,让短链可以被程序调用
源码自带的表单只能人工操作,团队接入后大概率要脚本批量生成,所以补一个 JSON API 是刚需。在入口文件前部加一段分支:
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_GET['api'])) { header('Content-Type: application/json; charset=utf-8'); $longUrl = trim((string)($_POST['url'] ?? '')); if ($longUrl === '' || !filter_var($longUrl, FILTER_VALIDATE_URL)) { echo json_encode(['code' => 1, 'msg' => 'url 参数不合法']); exit; } // 入库、生成短码,逻辑复用生成函数 $stmt = $pdo->prepare('INSERT INTO short_urls (short_code, long_url) VALUES (NULL, ?)'); $stmt->execute([$longUrl]); $id = (int)$pdo->lastInsertId(); $code = generateShortCode($pdo, $id); $stmt = $pdo->prepare('UPDATE short_urls SET short_code = ? WHERE id = ?'); $stmt->execute([$code, $id]); echo json_encode([ 'code' => 0, 'data' => [ 'short_url' => SITE_URL . $code, 'short_code' => $code, ], ]); exit; }接口返回 JSON 而不是 HTML,调用方拿 short_url 直接落库或拼接,不用解析页面。里面有四个注意点:
- 用 POST 而不是 GET。GET 虽然能做,但短链生成是写操作,GET 会被浏览器预加载、爬虫抓取,产生无意义的大量记录。
- filter_var + FILTER_VALIDATE_URL 做初步校验,能拦住明显非法值,但拦不住“存在但不属于你的域名”的链接。内部系统建议再加一层域名白名单。
- 事务要包住 INSERT 和 UPDATE。上面代码为了直观省略了 beginTransaction/commit,实际生产建议包上,避免生成一半失败留下 short_code 为 NULL 的垃圾行。
- json_encode 把关联数组转成 JSON 对象,前端拿到就是标准的
data.short_url结构,不需要额外处理序列化字符串。
到这里,这个源码包的改动已经从“能跑”变成“能被程序调用”。剩下的工作围绕安全和运营展开,见下一章的踩坑记录。
5. 部署排查与避坑:5 个跑起来之后才暴露的问题
短链接源码功能简单,坑都在配置和边界上。以下是我在不同环境里反复遇到、以及帮别人排查时最常见的五类问题,按现象、原因、解决三个角度写。
5.1 短链接一访问就 404:先分清是 PHP 还是 Nginx 的问题
现象:后台生成的短链接,浏览器访问提示 404,但直接在地址栏访问/index.php?code=abc却正常。
原因:伪静态规则没生效。常见三种:一是 Nginx 站点没加载 rewrite 规则;二是规则里的正则是^/[a-z]+$,而你的短码以数字开头;三是宝塔开了“防跨站”或 open_basedir,把 index.php 的实际路径挡了。
解决:先用 curl 验证:
curl -I http://你的域名/abc123 curl -I "http://你的域名/index.php?code=abc123"第一条返回 Nginx 的 404、第二条返回 302,那就是伪静态没接上。把正则扩成^([a-zA-Z0-9]+)$,确认 rewrite 的 target 是相对路径 index.php。如果两条都 500,去看 PHP-FPM 日志,而不是 Web 日志。
5.2 带中文参数的长链接跳转后乱码
现象:长链接里有中文或 urlencode 后的%E4%B8%AD之类,点击短链后落地页参数变成乱码,甚至直接 400。
原因:链路里的字符集不一致。要么是 MySQL 连接字符集不是 utf8mb4,要么是 header('Location: ...') 带了浏览器不能识别的原始中文。
解决:config.php 里 DSN 必须带 charset=utf8mb4,这在第 4 章 db.php 里已经强调。入库前对长链接做一次规范化:
$longUrl = filter_var($longUrl, FILTER_VALIDATE_URL); $longUrl = str_replace(' ', '%20', $longUrl); $longUrl = mb_convert_encoding($longUrl, 'UTF-8', 'auto');关键在 mb_convert_encoding 的第三个参数 auto:它会自动识别来源编码并转成 UTF-8。配合 DSN 里的 utf8mb4,整条链路就统一了。如果你是在 Windows 本机解压调试,还要确认源文件本身是 UTF-8 无 BOM,用 VSCode 或 phpstorm 打开右下角编码选 UTF-8 再保存。
5.3 PHP 8.3 环境下的 deprecated 报错与兼容处理
现象:源码是 PHP 5.6 时代写的,升级到 PHP 8.3 后页面顶部冒出一行 Deprecated,或者直接白屏,错误日志里全是 “Creation of dynamic property”。
原因:PHP 7.4 起对动态属性发警告,8.2 起变成废弃,8.3 里某些写法直接移除。短链接源码里最常见的是类里不声明属性就直接$this->db = ...,以及字符串偏移用花括号$str{0}这种老语法。
解决:优先改代码而不是降 PHP 版本。动态属性在类定义里显式声明:
class ShortUrl { public $db; // 显式声明,兼容 PHP 8.x public $table = 'short_urls'; public function __construct($pdo) { $this->db = $pdo; } }花括号偏移改成方括号$str[0]。如果暂时不想动代码,可以在入口文件做兼容层:error_reporting(E_ALL & ~E_DEPRECATED)压掉提示,但这是治标。PHP 错误处理上建议把 E_DEPRECATED 单独记日志,慢慢改干净。
5.4 并发生成时短码重复:问题出在检查和插入的顺序
现象:用脚本连续批量生成 500 条,偶发出现两条记录 short_code 一样,导致后生成的短链接打到了先前的长链接上。
原因:先 SELECT 查重再 INSERT 的方式在并发下有竞态条件。两个请求同时发现某短码不存在,然后同时插入,后插入的覆盖或报错,取决于有没有唯一索引。
解决:给 short_code 建 UNIQUE KEY,这是硬约束;同时把插入和生成改成捕获 1062 冲突后重试:
for ($i = 0; $i < 3; $i++) { $code = encode62($id + $i * 997); // 用固定步长错开候选 try { $stmt = $pdo->prepare('INSERT INTO short_urls (short_code, long_url) VALUES (?, ?)'); $stmt->execute([$code, $longUrl]); break; } catch (PDOException $e) { if ($e->errorInfo[1] !== 1062) { throw $e; // 1062 是唯一键冲突,其他错误照常抛出 } // 冲突,进下一轮循环 } }这里把“查重”完全交给数据库,应用层只负责在异常码 1062 时换个候选短码重试。步长 997 是随手选的质数,保证重试候选和原 ID 不发生周期性重复。
5.5 黑色主题样式全丢:多半是静态资源被伪静态吞了
现象:访问短链接跳转正常,但打开生成表单页面没有 CSS,整个黑色主题变成白底黑字的裸 HTML。
原因:伪静态规则写成了把所有不存在路径都重写到 index.php,而站里如果用相对路径引用 static/style.css,会在某个短码路径下被解析成/短码/style.css,返回的却是 index.php 的 200 页面,浏览器自然不认。
解决:伪静态规则里必须保留静态资源直通:
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ { expires 7d; try_files $uri =404; }同时前端模板里尽量用绝对路径/static/style.css,而不是static/style.css。少了开头斜杠,在嵌套路径下会相对当前路径解析,出一堆 404。短链服务因为跳转路径都是单层短码,最容易触发这个问题。
6. 进阶玩法:点击统计、自定义短码与批量生成的落地
短链接跑通之后,下一件事通常是问“能不能看到谁点了”。最小可用的统计不需要引入第三方,在跳转前记一条日志就行。
6.1 跳转处记一笔日志:不伤性能的落库方式
在 4.1 的跳转分支里,把 hits 字段更新和日志表插入分开处理。更新 hits 是最简单的计数;如果想看来源,建一张 short_logs 表,记录短码、Referer、User-Agent、IP。每次跳转都插一条,量一大就写不动,常见做法是异步落库——把日志先写到本地文件,再用 cron 每分钟批量导入。PHP 实现里最简单的异步就是:
// 跳转前只追加一行日志文件,不碰数据库 $line = json_encode([ 'code' => $code, 'time' => time(), 'ua' => $_SERVER['HTTP_USER_AGENT'] ?? '', 'ip' => $_SERVER['REMOTE_ADDR'] ?? '', ]); file_put_contents('/var/log/shorturl/access.log', $line . PHP_EOL, FILE_APPEND);Append 模式比开数据库连接快得多,也不阻塞跳转响应。cron 脚本再按行解析,UPDATE short_urls SET hits = hits + 1,并写入明细表。这样跳转耗时只多了一次文件追加,代价是可容忍的。
6.2 自定义短码与批量导入
运营要的是“自定义后缀”:活动名、渠道名直接拼成短码。实现上先生成,再校验唯一:
function isCodeAvailable(PDO $pdo, string $code): bool { $stmt = $pdo->prepare('SELECT COUNT(*) FROM short_urls WHERE short_code = ?'); $stmt->execute([$code]); return (int)$stmt->fetchColumn() === 0; }注意自定义短码只允许字母数字,校验规则写成/^[a-zA-Z0-9]{4,12}$/,太短容易被遍历,太长失去短链意义。批量导入时把 CSV 解析和 6.1 的日志脚本结合,用 CLI 模式跑,别走 Web 请求,避免超时。
我自己现在搭短链服务,第一件事总是把默认的 301 换成 302,因为这直接决定统计数据完整不缺;然后给 short_code 加唯一索引,因为这是后面一切功能的地基。等跑顺一阵子,再回头看要不要加热度排行、二维码接口这些锦上添花的东西。希望这篇能帮你的短链接项目少走几趟弯路,直接落到能用的状态。
本文还有配套的精品资源,点击获取