133 lines
4.3 KiB
TypeScript
133 lines
4.3 KiB
TypeScript
import type { IncomingMessage } from 'node:http'
|
|
import { loadEnv, mergeConfig, type ConfigEnv, type ProxyOptions } from 'vite'
|
|
// import eslint from 'vite-plugin-eslint'
|
|
import baseConfig from './vite.config.base'
|
|
|
|
const HIKVISION_PROXY_TIMEOUT = 8000
|
|
|
|
const proxyTarget = (port: number) => ({
|
|
target: `http://127.0.0.1:${port}`,
|
|
changeOrigin: true,
|
|
})
|
|
|
|
/** 读取海康 WebSDK 写入的代理目标 Cookie。 */
|
|
function getProxyCookie(request: IncomingMessage, name: string): string {
|
|
const cookie = request.headers.cookie || ''
|
|
const matched = cookie.match(new RegExp(`(?:^|;\\s*)${name}=([^;]+)`))
|
|
if (!matched) return ''
|
|
try {
|
|
return decodeURIComponent(matched[1])
|
|
} catch (_error) {
|
|
return ''
|
|
}
|
|
}
|
|
|
|
/** 从 SDK Cookie 解析 WebSocket 端口,并限制只能代理到已配置的录像机。 */
|
|
function resolveHikvisionWebSocketTarget(request: IncomingMessage, allowedHost: string, fallbackTarget: string): string {
|
|
const secureAddress = getProxyCookie(request, 'webVideoCtrlProxyWss')
|
|
const address = secureAddress || getProxyCookie(request, 'webVideoCtrlProxyWs')
|
|
if (!address) return fallbackTarget
|
|
try {
|
|
const target = new URL(`${secureAddress ? 'wss' : 'ws'}://${address}`)
|
|
return target.hostname.toLowerCase() === allowedHost.toLowerCase() ? target.toString() : fallbackTarget
|
|
} catch (_error) {
|
|
return fallbackTarget
|
|
}
|
|
}
|
|
|
|
/** 创建开发环境 Vite 配置。 */
|
|
export default ({ mode }: ConfigEnv) => {
|
|
const env = loadEnv(mode, process.cwd(), '')
|
|
const apiProxyTarget = env.VITE_API_PROXY_TARGET || 'https://ops-api.apinb.com'
|
|
const proxy: Record<string, ProxyOptions> = {
|
|
'/api': {
|
|
target: apiProxyTarget,
|
|
changeOrigin: true,
|
|
ws: true,
|
|
rewrite: (path) => path.replace(/^\/api/, ''),
|
|
},
|
|
'/rbac2': proxyTarget(10001),
|
|
'/Alert': proxyTarget(12427),
|
|
'/alert': proxyTarget(12427),
|
|
'/DC-Control': proxyTarget(3031),
|
|
'/dc-control': proxyTarget(3031),
|
|
'/dc-network': proxyTarget(12429),
|
|
'/DC-Hardware': proxyTarget(12450),
|
|
'/dc-hardware': proxyTarget(12450),
|
|
'/dc-host': proxyTarget(9030),
|
|
'/dc-middleware': proxyTarget(12428),
|
|
'/dc-database': proxyTarget(12580),
|
|
'/Feedback': proxyTarget(12432),
|
|
'/feedback': proxyTarget(12432),
|
|
'/Assets': proxyTarget(12430),
|
|
'/assets': proxyTarget(12430),
|
|
'/Logs': proxyTarget(12440),
|
|
'/logs': proxyTarget(12440),
|
|
'/Kb': proxyTarget(12434),
|
|
'/kb': proxyTarget(12434),
|
|
'/Mgt': proxyTarget(12436),
|
|
'/mgt': proxyTarget(12436),
|
|
'/Visual': proxyTarget(12438),
|
|
'/visual': proxyTarget(12438),
|
|
}
|
|
|
|
if (env.VITE_HIKVISION_PROXY_TARGET) {
|
|
const hikvisionHttpTarget = new URL(env.VITE_HIKVISION_PROXY_TARGET)
|
|
const hikvisionWebSocketTarget =
|
|
env.VITE_HIKVISION_WS_PROXY_TARGET || `${hikvisionHttpTarget.protocol === 'https:' ? 'wss' : 'ws'}://${hikvisionHttpTarget.host}`
|
|
proxy['/ISAPI'] = {
|
|
target: env.VITE_HIKVISION_PROXY_TARGET,
|
|
changeOrigin: true,
|
|
secure: false,
|
|
timeout: HIKVISION_PROXY_TIMEOUT,
|
|
proxyTimeout: HIKVISION_PROXY_TIMEOUT,
|
|
}
|
|
proxy['/SDK'] = {
|
|
target: env.VITE_HIKVISION_PROXY_TARGET,
|
|
changeOrigin: true,
|
|
secure: false,
|
|
timeout: HIKVISION_PROXY_TIMEOUT,
|
|
proxyTimeout: HIKVISION_PROXY_TIMEOUT,
|
|
}
|
|
proxy['/webSocketVideoCtrlProxy'] = {
|
|
target: hikvisionWebSocketTarget,
|
|
changeOrigin: true,
|
|
secure: false,
|
|
ws: true,
|
|
timeout: HIKVISION_PROXY_TIMEOUT,
|
|
proxyTimeout: HIKVISION_PROXY_TIMEOUT,
|
|
router: env.VITE_HIKVISION_WS_PROXY_TARGET
|
|
? undefined
|
|
: (request) => resolveHikvisionWebSocketTarget(request, hikvisionHttpTarget.hostname, hikvisionWebSocketTarget),
|
|
rewrite: (path) => path.replace(/^\/webSocketVideoCtrlProxy/, '/'),
|
|
}
|
|
}
|
|
|
|
return mergeConfig(
|
|
{
|
|
mode: 'development',
|
|
server: {
|
|
open: true,
|
|
host: '0.0.0.0',
|
|
headers: {
|
|
'Cross-Origin-Embedder-Policy': 'require-corp',
|
|
'Cross-Origin-Opener-Policy': 'same-origin',
|
|
'Cross-Origin-Resource-Policy': 'cross-origin',
|
|
},
|
|
fs: {
|
|
strict: true,
|
|
},
|
|
proxy,
|
|
},
|
|
plugins: [
|
|
// eslint({
|
|
// cache: false,
|
|
// include: ['src/**/*.ts', 'src/**/*.tsx', 'src/**/*.vue'],
|
|
// exclude: ['node_modules'],
|
|
// }),
|
|
],
|
|
},
|
|
baseConfig
|
|
)
|
|
}
|