短链接 API 本地就能跑:Express + Node 实战
一、背景:短链接服务,自己写一个也就几十行
本文用 Express 写一个最小短链接服务:POST 原 URL 返回一个短码,GET 短码 302 跳回原 URL,映射存在内存里(演示用,重启即丢,真实用请换持久化)。讲清路由、重定向头和内存存储的取舍。具体 API 以 Express 官方文档为准。
二、服务骨架:两条路由
const express = require('express')
const app = express()
app.use(express.json())
const map = {} // 短码 -> 原URL,内存存储
app.post('/create', (req, res) => {
const url = req.body.url
const code = Math.random().toString(36).slice(2, 8) // 6位短码
map[code] = url
res.json({ short: code, origin: url })
})
app.get('/:code', (req, res) => {
const origin = map[req.params.code]
if (!origin) return res.status(404).send('not found')
res.redirect(302, origin) // 关键:302 跳回
})
app.listen(3000, () => console.log('on 3000'))
app.use(express.json()) 让 POST 的 JSON body 能被 req.body 读到。/create 用 Math.random().toString(36) 生成 6 位短码、存进 map、返回。/:code 是动态路由,req.params.code 拿到路径里的短码,查到就 res.redirect(302, origin) 跳转、查不到 404。监听 3000,本地访问 localhost:3000/abc 就跳。整个服务不到 20 行。
三、重定向码:302 还是 301
res.redirect 默认是 302(临时重定向)。对短链接,302 和 301 语义不同:
- 302 临时:每次访问都回源查
map,便于统计点击量、便于改映射(改了下次访问就生效); - 301 永久:浏览器会缓存,之后不再问你服务器,直接跳。省一次请求,但你想改映射、做点击统计就难了。
短链接一般要能统计点击、可能要改目标,所以用 302 更合适。若要纯跳转省事、且目标永不改,才用 301。明确写 res.redirect(302, origin) 比依赖默认值更可读。
四、短码生成与冲突
上面 Math.random().toString(36).slice(2,8) 是随机 6 位短码,撞车概率极低但非零。更稳的做法是"基于原 URL 哈希"或"查重":
function genCode(url) {
let code
do { code = Math.random().toString(36).slice(2, 8) }
while (map[code]) // 已存在就重生成
return code
}
写前先查 map[code] 是否已占用,占用就重来,避免覆盖别人已有的映射。如果是"同一长链始终同一短码",就用 URL 哈希做 key(如 code = hash(url).slice(0,6)),天然不冲突、还能顺带做"重复创建返回同一短码"。两种策略按需求选。
五、几个要注意的点
第一,内存存储重启即丢。演示用 map 在内存,服务一重启所有短链接没了。真实要持久化:换 Redis(见前面 DCS 那篇)、换数据库(见 RDS 那篇),把 map 的读写换成存储操作即可,路由逻辑不变。本文定位"本地临时服务",接受重启丢失。
第二,没鉴权会被乱用。/create 完全公开,任何人都能拿你的服务发短链,可能被用来做跳转钓鱼。本地自用无所谓;若要给别人用,至少加个简单 key(请求带 ?key=xxx 校验)或限流,别裸奔。
第三,URL 合法性校验。直接把 req.body.url 当跳转目标,若有人传 javascript:... 或内部地址,虽浏览器对 302 的 Location 有限制,但严谨起见应校验协议白名单(只允 http/https),避免被当成开放重定向器(open redirect)滥用。校验一行:if (!/^https?:\/\//.test(url)) return 400。
第四,并发写 map。Node 单线程,普通 map[code]=url 不会有线程竞态;但如果是多进程(cluster)或换到外部存储,写入要原子(先查后写可能竞态),用存储的 SETNX 类原子操作保证不覆盖。单进程演示不用管。
第五,短码长度。6 位 36 进制约 20 亿组合,够个人用;若面向公网海量,考虑加长或加字符集。码越长越不"短",是取舍。
六、小结
Express 写短链接服务极轻:两条路由——/create 生成短码存内存、/:code 查到 302 跳回。302 适合要统计/可改映射,301 适合纯永久跳转。短码用随机+查重防覆盖,或哈希保一致。演示用内存 map 重启即丢,上线换 Redis/数据库即可、map 读写换成存储操作、路由不变。注意 /create 加鉴权、跳转目标校验 http(s) 防开放重定向。Express 路由与 redirect 以官方文档为准。
- 点赞
- 收藏
- 关注作者
评论(0)