短链接 API 本地就能跑:Express + Node 实战

举报
静水流深-云海 发表于 2026/10/15 10:48:46 2026/10/15
【摘要】 用 Express + Node 写本地短链接服务:/create 生成短码存内存、/:code 查到 302 跳转。讲清 302/301 区别、短码查重防冲突、URL 白名单校验防开放重定向,内存存储重启即丢需换持久化。

一、背景:短链接服务,自己写一个也就几十行

本文用 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 以官方文档为准。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。