diff --git a/src/webui/src/helper/config.ts b/src/webui/src/helper/config.ts index c03d8535..14342aaa 100644 --- a/src/webui/src/helper/config.ts +++ b/src/webui/src/helper/config.ts @@ -7,12 +7,12 @@ import { resolve } from 'node:path'; import { deepMerge } from '../utils/object'; import { themeType } from '../types/theme'; -import { getRandomToken } from '../utils/url' +import { getRandomToken, getDefaultHost } from '../utils/url' // 限制尝试端口的次数,避免死循环 // 定义配置的类型 const WebUiConfigSchema = Type.Object({ - host: Type.String({ default: '127.0.0.1' }), + host: Type.String({ default: getDefaultHost() }), port: Type.Number({ default: 6099 }), token: Type.String({ default: getRandomToken(8) }), loginRate: Type.Number({ default: 10 }), diff --git a/src/webui/src/utils/url.ts b/src/webui/src/utils/url.ts index 8edf6e96..0df403b0 100644 --- a/src/webui/src/utils/url.ts +++ b/src/webui/src/utils/url.ts @@ -1,10 +1,58 @@ /** * @file URL工具 */ - -import { isIP } from 'node:net'; +import fs from 'node:fs' +import { isIP } from 'node:net' import { randomBytes } from 'node:crypto' +type Protocol = 'http' | 'https' + +let isDockerCached: boolean + +function hasDockerEnv () { + try { + fs.statSync('/.dockerenv') + return true + } catch { + return false + } +} + +function hasDockerCGroup () { + try { + return fs.readFileSync('/proc/self/cgroup', 'utf8').includes('docker') + } catch { + return false + } +} + +const hasContainerEnv = () => { + try { + fs.statSync('/run/.containerenv') + return true + } catch { + return false + } +} + +const isDocker = () => { + if (isDockerCached === undefined) { + isDockerCached = hasContainerEnv() || hasDockerEnv() || hasDockerCGroup() + } + + return isDockerCached +} + +/** + * 获取默认host地址 + * @returns 根据环境返回合适的host地址 + * @example getDefaultHost() => '127.0.0.1' // 非Docker环境 + * @example getDefaultHost() => '0.0.0.0' // Docker环境 + */ +export const getDefaultHost = (): string => { + return isDocker() ? '0.0.0.0' : '127.0.0.1' +} + /** * 将 host(主机地址) 转换为标准格式 * @param host 主机地址 @@ -14,9 +62,9 @@ import { randomBytes } from 'node:crypto' * @example normalizeHost('2001:4860:4801:51::27') => '[2001:4860:4801:51::27]' */ export const normalizeHost = (host: string) => { - if (isIP(host) === 6) return `[${host}]`; - return host; -}; + if (isIP(host) === 6) return `[${host}]` + return host +} /** * 创建URL @@ -35,16 +83,16 @@ export const createUrl = ( search?: Record, protocol: Protocol = 'http' ) => { - const url = new URL(`${protocol}://${normalizeHost(host)}`); - url.port = port; - url.pathname = path; + const url = new URL(`${protocol}://${normalizeHost(host)}`) + url.port = port + url.pathname = path if (search) { for (const key in search) { - url.searchParams.set(key, search[key]); + url.searchParams.set(key, search[key]) } } - return url.toString(); -}; + return url.toString() +} /** * 生成随机Token @@ -53,5 +101,5 @@ export const createUrl = ( * @example getRandomToken */ export const getRandomToken = (length = 8) => { - return randomBytes(36).toString('hex').slice(0, length); + return randomBytes(36).toString('hex').slice(0, length) }