---
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=N与application/json;默认版本回退到1;最大版本为3。 - 不支持版本或类型返回
406;响应头包含版本化Content-Type;路由映射按版本选择。

发表评论 取消回复