2026-01-02 17:40:57 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 验证并规范化 URL
|
|
|
|
|
|
* 默认只接受绝对 URL(以 http:// 或 https:// 开头),可按需允许相对路径
|
|
|
|
|
|
* @param value 用户输入的 URL
|
|
|
|
|
|
* @returns 规范化后的 URL,如果无效则返回空字符串
|
|
|
|
|
|
*/
|
|
|
|
|
|
type SanitizeOptions = {
|
|
|
|
|
|
allowRelative?: boolean
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function sanitizeUrl(value: string, options: SanitizeOptions = {}): string {
|
|
|
|
|
|
const trimmed = value.trim()
|
|
|
|
|
|
if (!trimmed) {
|
|
|
|
|
|
return ''
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-03 10:52:24 +08:00
|
|
|
|
if (options.allowRelative && trimmed.startsWith('/') && !trimmed.startsWith('//')) {
|
2026-01-02 17:40:57 +08:00
|
|
|
|
return trimmed
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 只接受绝对 URL,不使用 base URL 来避免相对路径被解析为当前域名
|
|
|
|
|
|
// 检查是否以 http:// 或 https:// 开头
|
|
|
|
|
|
if (!trimmed.match(/^https?:\/\//i)) {
|
|
|
|
|
|
return ''
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const parsed = new URL(trimmed)
|
|
|
|
|
|
const protocol = parsed.protocol.toLowerCase()
|
|
|
|
|
|
if (protocol !== 'http:' && protocol !== 'https:') {
|
|
|
|
|
|
return ''
|
|
|
|
|
|
}
|
|
|
|
|
|
return parsed.toString()
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
return ''
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|