---

title: API版本治理与媒体类型协商最佳实践

keywords:

  • 版本治理
  • 媒体类型
  • Accept
  • Content-Type
  • vnd
  • 兼容
  • 406
  • 默认版本
  • 路由映射
  • 响应协商

description: 通过媒体类型与Accept头进行版本协商,统一默认与最大版本策略,按路由映射返回对应版本的响应,并在不支持时返回406,附解析与选择示例。

categories:

  • 文章资讯
  • 技术教程

---

一、解析与默认策略

type Req = { headers: Record<string, string | undefined>; path: string }
type Res = { setHeader: (k: string, v: string) => void; status: (n: number) => Res; end: (b?: string) => void }

function parseAccept(accept: string | undefined): { type: string; version?: number } {
  const a = accept || ''
  const m = a.match(/application\/vnd\.app\+json;\s*version=(\d+)/i)
  if (m) return { type: 'application/vnd.app+json', version: Number(m[1]) }
  if (a.includes('application/json')) return { type: 'application/json' }
  return { type: '' }
}

const DEFAULT_VERSION = 1
const MAX_VERSION = 3

二、版本选择与校验

function selectVersion(acc: { type: string; version?: number }): number {
  if (acc.version && acc.version >= 1 && acc.version <= MAX_VERSION) return acc.version
  return DEFAULT_VERSION
}

function unsupported(acc: { type: string; version?: number }): boolean {
  if (acc.type === '') return true
  if (acc.version && (acc.version < 1 || acc.version > MAX_VERSION)) return true
  return false
}

三、路由映射与响应

type Handler = (req: Req, res: Res) => void
const routes: Record<string, Record<number, Handler>> = {
  '/users': {
    1: (req, res) => { res.setHeader('Content-Type', 'application/vnd.app+json; version=1'); res.end(JSON.stringify({ users: [{ id: 1, name: 'a' }] })) },
    2: (req, res) => { res.setHeader('Content-Type', 'application/vnd.app+json; version=2'); res.end(JSON.stringify({ data: { users: [{ id: 1, name: 'a', email: 'x@y' }] } })) },
    3: (req, res) => { res.setHeader('Content-Type', 'application/vnd.app+json; version=3'); res.end(JSON.stringify({ result: { items: [{ id: 1, name: 'a', email: 'x@y', roles: ['user'] }] } })) }
  }
}

四、协商流程与验收

function handle(req: Req, res: Res) {
  const acc = parseAccept(req.headers['accept'])
  if (unsupported(acc)) return res.status(406).end('not_acceptable')
  const v = selectVersion(acc)
  const table = routes[req.path]
  const h = table?.[v]
  if (!h) return res.status(404).end('not_found')
  h(req, res)
}
  • Accept解析支持application/vnd.app+json; version=Napplication/json;默认版本回退到1;最大版本为3
  • 不支持版本或类型返回406;响应头包含版本化Content-Type;路由映射按版本选择。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部