Files
BYW-VoiceHub/server/middleware/api-cors.ts
T
Henry_Du 4ce4649aaf
Build VoiceHub FPK / build-fpk (push) Failing after 56m5s
Build and Push Docker Image / build-and-push (push) Canceled after 1h9m35s
初次提交
2026-09-06 08:19:02 +08:00

85 lines
3.2 KiB
TypeScript

export default defineEventHandler((event) => {
const pathname = getRequestURL(event).pathname
// 只处理特定的内部API路由,防止站外调用
const isProtectedApi = pathname.startsWith('/api/api-enhanced/netease') ||
pathname.startsWith('/api/native-api')
if (!isProtectedApi) {
return
}
// CORS 限制:禁止站外网站调用
const origin = getHeader(event, 'origin')
const referer = getHeader(event, 'referer')
const secFetchSite = getHeader(event, 'sec-fetch-site')
const sourceUrl = origin || referer
if (sourceUrl) {
try {
const url = new URL(sourceUrl)
const extractHostname = (value: string) => {
const normalizedValue = value.includes('://') ? value : `http://${value}`
return new URL(normalizedValue).hostname
}
// 获取当前请求的 hostname,优先使用配置中可信的主机名,防止 x-forwarded-host 伪造攻击
const config = useRuntimeConfig(event)
const configuredHost = config.public?.host
let requestHostname: string
if (configuredHost) {
requestHostname = extractHostname(configuredHost)
} else {
// 只有在未配置公网主机名时,才回退到 host 请求头
const hostHeader = getHeader(event, 'host')
if (hostHeader) {
requestHostname = extractHostname(hostHeader)
} else {
// 缺少 Host 请求头,这是一个异常情况,应该拒绝请求
throw createError({ statusCode: 400, message: 'Bad Request: 缺少Host请求头' })
}
}
const isLocalhost = (h: string) => h === 'localhost' || h === '127.0.0.1' || h === '[::1]'
// 如果来源域与当前域不一致,则拒绝请求
// 注意:允许 localhost 和 127.0.0.1 之间的互访
if (url.hostname !== requestHostname && !(isLocalhost(url.hostname) && isLocalhost(requestHostname))) {
console.warn(`[CORS Middleware] 拦截跨域请求: 来源 ${url.hostname}, 期望 ${requestHostname}, 路径 ${pathname}`)
throw createError({
statusCode: 403,
message: 'Forbidden: 内部API不允许跨域请求'
})
}
} catch (e: unknown) {
// 如果是我们主动抛出的 HTTP 错误,则重新抛出
if (
typeof e === 'object' &&
e !== null &&
'statusCode' in e &&
typeof e.statusCode === 'number'
) {
throw e
}
// 对于其他错误(如无效的URL),这是一个错误的请求
console.warn(`[CORS Middleware] 无效的来源 URL: ${sourceUrl}`, e)
throw createError({
statusCode: 400,
message: 'Bad Request: Origin或Referer头无效'
})
}
} else if (secFetchSite === 'same-origin') {
// 允许没有 Origin/Referer 但明确标记为同源的请求
return
} else {
// 拦截没有来源信息的受保护API请求
console.warn(`[CORS Middleware] 拦截无Origin/Referer头的请求: 路径 ${pathname}, sec-fetch-site: ${secFetchSite || 'none'}`)
throw createError({
statusCode: 403,
message: 'Forbidden: 访问此API必须提供Origin或Referer头'
})
}
})