fix(nginx): WebSocket trailing slash, 413 on file upload, domain+HTTPS support
- nginx: /ws/im/ → /ws/im (trailing slash broke ?token= WebSocket connections) - nginx: add /api/file/ location before /api/ with 500m limit (fixes 413) - deploy.sh: default DEPLOY_HOST to localhost instead of 127.0.0.1 - deploy.sh: add interactive domain/HTTPS configuration step (0c) - optional custom domain with validation - optional HTTPS via Let's Encrypt certbot (standalone, before nginx starts) - generates SSL nginx config (two-server-block) and docker-compose.override.yml - SDK_IM_WS_URL and imWsUrl use _WS_SCHEME (ws/wss) based on protocol - deploy.sh: add info() helper function Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
父节点
be04c311b9
当前提交
d2599a0c1e
@ -63,8 +63,9 @@ server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# IM WebSocket 长连接(客户端消息收发)
|
# IM WebSocket 长连接(客户端消息收发)
|
||||||
location /ws/im/ {
|
# 注意:不加尾部斜杠,否则 /ws/im?token=xxx 不匹配(nginx prefix matching 不含 ?)
|
||||||
proxy_pass http://im-service:8082/ws/im/;
|
location /ws/im {
|
||||||
|
proxy_pass http://im-service:8082/ws/im;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "upgrade";
|
proxy_set_header Connection "upgrade";
|
||||||
@ -83,6 +84,18 @@ server {
|
|||||||
proxy_read_timeout 60s;
|
proxy_read_timeout 60s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ----------- 文件服务 API 路径(file-service:8086)-----------
|
||||||
|
# 注意:必须在通用 /api/ 之前声明,防止走 tenant-service 的 100m 限制
|
||||||
|
location /api/file/ {
|
||||||
|
proxy_pass http://file-service:8086/api/file/;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
client_max_body_size 500m;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
proxy_send_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
# ----------- 核心 API(tenant-service:9001)-----------
|
# ----------- 核心 API(tenant-service:9001)-----------
|
||||||
# 注意:tenant-service 运行在 9001 端口(不是 8080)
|
# 注意:tenant-service 运行在 9001 端口(不是 8080)
|
||||||
# 包含:认证、租户管理、App 管理、SDK 配置、私有化部署状态
|
# 包含:认证、租户管理、App 管理、SDK 配置、私有化部署状态
|
||||||
|
|||||||
@ -21,8 +21,8 @@
|
|||||||
# - 在 XuqmGroup-PrivateDeploy 仓库根目录下执行本脚本
|
# - 在 XuqmGroup-PrivateDeploy 仓库根目录下执行本脚本
|
||||||
#
|
#
|
||||||
# 覆盖默认值(可通过环境变量传入):
|
# 覆盖默认值(可通过环境变量传入):
|
||||||
# DEPLOY_HOST 目标机器 IP / 主机名(默认 127.0.0.1)
|
# DEPLOY_HOST 目标机器 IP / 主机名(默认 localhost)
|
||||||
# 纯 IP 部署无需域名,局域网内可全功能使用
|
# 部署向导会提示配置域名与 HTTPS
|
||||||
# REGISTRY_PASSWORD ACR 密码(默认 xuqinmin1022)
|
# REGISTRY_PASSWORD ACR 密码(默认 xuqinmin1022)
|
||||||
# MYSQL_ROOT_PASSWORD、MYSQL_PASSWORD、REDIS_PASSWORD 同理
|
# MYSQL_ROOT_PASSWORD、MYSQL_PASSWORD、REDIS_PASSWORD 同理
|
||||||
|
|
||||||
@ -42,8 +42,12 @@ IMAGE_TAG="latest"
|
|||||||
|
|
||||||
# 部署主机(用于健康检查 HTTP 请求)
|
# 部署主机(用于健康检查 HTTP 请求)
|
||||||
# 可以是 IP 地址,无需域名,局域网内即可完整使用所有服务
|
# 可以是 IP 地址,无需域名,局域网内即可完整使用所有服务
|
||||||
DEPLOY_HOST="${DEPLOY_HOST:-127.0.0.1}"
|
DEPLOY_HOST="${DEPLOY_HOST:-localhost}"
|
||||||
CONSOLE_BASE="http://${DEPLOY_HOST}"
|
CONSOLE_BASE="http://${DEPLOY_HOST}"
|
||||||
|
_HTTP_SCHEME="http"
|
||||||
|
_WS_SCHEME="ws"
|
||||||
|
DEPLOY_DOMAIN=""
|
||||||
|
USE_HTTPS=false
|
||||||
|
|
||||||
# MySQL(managed 模式,由 Docker 容器托管)
|
# MySQL(managed 模式,由 Docker 容器托管)
|
||||||
MYSQL_ROOT_PASSWORD="${MYSQL_ROOT_PASSWORD:-XuqmRoot@2026}"
|
MYSQL_ROOT_PASSWORD="${MYSQL_ROOT_PASSWORD:-XuqmRoot@2026}"
|
||||||
@ -68,6 +72,7 @@ TOTAL_STEPS=8
|
|||||||
# 工具函数
|
# 工具函数
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
log() { printf '\n\033[1;36m[%d/%d] %s\033[0m\n' "$STEP" "$TOTAL_STEPS" "$*"; }
|
log() { printf '\n\033[1;36m[%d/%d] %s\033[0m\n' "$STEP" "$TOTAL_STEPS" "$*"; }
|
||||||
|
info() { printf ' \033[1;36m→\033[0m %s\n' "$*"; }
|
||||||
ok() { printf ' \033[32m✓\033[0m %s\n' "$*"; }
|
ok() { printf ' \033[32m✓\033[0m %s\n' "$*"; }
|
||||||
warn() { printf ' \033[33m⚠\033[0m %s\n' "$*"; }
|
warn() { printf ' \033[33m⚠\033[0m %s\n' "$*"; }
|
||||||
fail() { printf '\n\033[1;31mERROR: %s\033[0m\n' "$*" >&2; exit 1; }
|
fail() { printf '\n\033[1;31mERROR: %s\033[0m\n' "$*" >&2; exit 1; }
|
||||||
@ -180,6 +185,40 @@ else
|
|||||||
_BOOTSTRAP_PASSWORD="already-migrated-do-not-use"
|
_BOOTSTRAP_PASSWORD="already-migrated-do-not-use"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# 0c. 域名 / HTTPS 配置(交互式)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
printf '\n\033[1;33m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m\n'
|
||||||
|
printf '\033[1;33m 访问域名配置(可选)\033[0m\n'
|
||||||
|
printf '\033[1;33m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m\n'
|
||||||
|
printf ' 默认使用 localhost(适合本机或局域网访问)\n'
|
||||||
|
printf ' 如有公网域名,可在此配置并自动申请 HTTPS 证书\n\n'
|
||||||
|
|
||||||
|
read -rp " 是否使用自定义域名?[y/N]: " _domain_yn
|
||||||
|
if [[ "${_domain_yn:-N}" =~ ^[Yy]$ ]]; then
|
||||||
|
while [ -z "$DEPLOY_DOMAIN" ]; do
|
||||||
|
read -rp " 请输入域名(如 xuqm.example.com,不含 http://): " DEPLOY_DOMAIN
|
||||||
|
if ! printf '%s' "$DEPLOY_DOMAIN" | grep -qE '^[a-zA-Z0-9][a-zA-Z0-9._-]+\.[a-zA-Z]{2,}$'; then
|
||||||
|
warn "域名格式不正确,请重新输入(例: xuqm.example.com)"
|
||||||
|
DEPLOY_DOMAIN=""
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
DEPLOY_HOST="$DEPLOY_DOMAIN"
|
||||||
|
|
||||||
|
read -rp " 是否配置 HTTPS(需域名已解析到本机,将自动申请 Let's Encrypt 证书)?[y/N]: " _https_yn
|
||||||
|
if [[ "${_https_yn:-N}" =~ ^[Yy]$ ]]; then
|
||||||
|
USE_HTTPS=true
|
||||||
|
_HTTP_SCHEME="https"
|
||||||
|
_WS_SCHEME="wss"
|
||||||
|
CONSOLE_BASE="https://${DEPLOY_DOMAIN}"
|
||||||
|
else
|
||||||
|
CONSOLE_BASE="http://${DEPLOY_DOMAIN}"
|
||||||
|
fi
|
||||||
|
ok "域名: ${DEPLOY_DOMAIN},协议: ${_HTTP_SCHEME}"
|
||||||
|
else
|
||||||
|
ok "使用默认地址: ${CONSOLE_BASE}"
|
||||||
|
fi
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Step 1 — 预检
|
# Step 1 — 预检
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@ -316,7 +355,7 @@ PUSH_DOMAIN=${CONSOLE_BASE}
|
|||||||
# SDK 对外服务地址(客户端 SDK 使用)
|
# SDK 对外服务地址(客户端 SDK 使用)
|
||||||
SDK_FILE_SERVICE_URL=${CONSOLE_BASE}
|
SDK_FILE_SERVICE_URL=${CONSOLE_BASE}
|
||||||
SDK_IM_API_URL=${CONSOLE_BASE}
|
SDK_IM_API_URL=${CONSOLE_BASE}
|
||||||
SDK_IM_WS_URL=ws://${DEPLOY_HOST}/ws/im
|
SDK_IM_WS_URL=${_WS_SCHEME}://${DEPLOY_HOST}/ws/im
|
||||||
|
|
||||||
# 系统 IM 通信应用 key(私有化服务间消息通知使用此 app_key 连接 IM 服务)
|
# 系统 IM 通信应用 key(私有化服务间消息通知使用此 app_key 连接 IM 服务)
|
||||||
# 与公有化平台 xuqinmin12 租户下的平台系统应用 key 保持一致
|
# 与公有化平台 xuqinmin12 租户下的平台系统应用 key 保持一致
|
||||||
@ -335,13 +374,192 @@ EOF
|
|||||||
chmod 600 "$ROOT_DIR/config/tenant/bootstrap.env"
|
chmod 600 "$ROOT_DIR/config/tenant/bootstrap.env"
|
||||||
ok "config/tenant/bootstrap.env 已写入 (chmod 600)"
|
ok "config/tenant/bootstrap.env 已写入 (chmod 600)"
|
||||||
|
|
||||||
# config/nginx/conf.d/xuqm.conf — 从仓库中的文件复制(不再内嵌 heredoc,避免两处维护)
|
# config/nginx/conf.d/xuqm.conf
|
||||||
mkdir -p "$ROOT_DIR/config/nginx/conf.d"
|
mkdir -p "$ROOT_DIR/config/nginx/conf.d"
|
||||||
NGINX_SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/config/nginx/conf.d/xuqm.conf"
|
NGINX_CONF_PATH="$ROOT_DIR/config/nginx/conf.d/xuqm.conf"
|
||||||
if [ ! -f "$NGINX_SRC" ]; then
|
if [ ! -f "$NGINX_CONF_PATH" ]; then
|
||||||
fail "nginx 配置文件不存在: $NGINX_SRC(请确保在仓库根目录运行本脚本)"
|
fail "nginx 配置文件不存在: $NGINX_CONF_PATH(请确保在仓库根目录运行本脚本)"
|
||||||
fi
|
fi
|
||||||
# (以下 heredoc 仅作本地备份,deploy 时以上面复制为准,此段不执行)
|
|
||||||
|
if $USE_HTTPS; then
|
||||||
|
# ── HTTPS 模式:安装 certbot → 申请证书 → 生成 SSL nginx 配置 → compose override ──
|
||||||
|
|
||||||
|
# 安装 certbot(若未安装)
|
||||||
|
if ! command -v certbot >/dev/null 2>&1; then
|
||||||
|
info "安装 certbot ..."
|
||||||
|
if [ "$(command -v apt-get)" ]; then
|
||||||
|
apt-get install -y -qq certbot 2>/dev/null || fail "certbot 安装失败,请手动执行: apt install certbot"
|
||||||
|
elif [ "$(command -v yum)" ]; then
|
||||||
|
yum install -y -q certbot 2>/dev/null || fail "certbot 安装失败,请手动执行: yum install certbot"
|
||||||
|
else
|
||||||
|
fail "无法自动安装 certbot,请手动安装后重新运行"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
ok "certbot $(certbot --version 2>&1 | head -1)"
|
||||||
|
|
||||||
|
# 申请 Let's Encrypt 证书(standalone,此时 nginx 尚未启动)
|
||||||
|
CERT_DIR="/etc/letsencrypt/live/${DEPLOY_DOMAIN}"
|
||||||
|
if [ -f "${CERT_DIR}/fullchain.pem" ]; then
|
||||||
|
ok "证书已存在,跳过申请: ${CERT_DIR}"
|
||||||
|
else
|
||||||
|
info "申请 Let's Encrypt 证书(域名: ${DEPLOY_DOMAIN},需要端口 80 可达)..."
|
||||||
|
certbot certonly --standalone -d "$DEPLOY_DOMAIN" \
|
||||||
|
--agree-tos --register-unsafely-without-email --non-interactive \
|
||||||
|
|| fail "证书申请失败,请确认域名 ${DEPLOY_DOMAIN} 已解析到本机且端口 80 可访问"
|
||||||
|
ok "证书已申请: ${CERT_DIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 生成包含 SSL 的 nginx 配置(覆盖仓库静态文件)
|
||||||
|
cat > "$NGINX_CONF_PATH" << NGINX_CONF
|
||||||
|
# =============================================================================
|
||||||
|
# XuqmGroup 私有化部署 — Nginx HTTPS 配置(由 deploy.sh 自动生成)
|
||||||
|
# 域名: ${DEPLOY_DOMAIN}
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# HTTP → HTTPS 重定向
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name ${DEPLOY_DOMAIN};
|
||||||
|
return 301 https://\$host\$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name ${DEPLOY_DOMAIN};
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/${DEPLOY_DOMAIN}/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/${DEPLOY_DOMAIN}/privkey.pem;
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
ssl_session_cache shared:SSL:10m;
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
|
||||||
|
charset utf-8;
|
||||||
|
client_max_body_size 100m;
|
||||||
|
|
||||||
|
location /health {
|
||||||
|
return 200 "ok\n";
|
||||||
|
add_header Content-Type text/plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v1/updates/ {
|
||||||
|
proxy_pass http://update-service:8084/api/v1/updates/;
|
||||||
|
proxy_set_header Host \$host;
|
||||||
|
proxy_set_header X-Real-IP \$remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 60s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v1/rn/ {
|
||||||
|
proxy_pass http://update-service:8084/api/v1/rn/;
|
||||||
|
proxy_set_header Host \$host;
|
||||||
|
proxy_set_header X-Real-IP \$remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 120s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/im/ {
|
||||||
|
proxy_pass http://im-service:8082/api/im/;
|
||||||
|
proxy_set_header Host \$host;
|
||||||
|
proxy_set_header X-Real-IP \$remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 60s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /ws/im {
|
||||||
|
proxy_pass http://im-service:8082/ws/im;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade \$http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host \$host;
|
||||||
|
proxy_set_header X-Real-IP \$remote_addr;
|
||||||
|
proxy_read_timeout 3600s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/license/ {
|
||||||
|
proxy_pass http://license-service:8085/api/license/;
|
||||||
|
proxy_set_header Host \$host;
|
||||||
|
proxy_set_header X-Real-IP \$remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 60s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/file/ {
|
||||||
|
proxy_pass http://file-service:8086/api/file/;
|
||||||
|
proxy_set_header Host \$host;
|
||||||
|
proxy_set_header X-Real-IP \$remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||||
|
client_max_body_size 500m;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
proxy_send_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass http://tenant-service:9001/api/;
|
||||||
|
proxy_set_header Host \$host;
|
||||||
|
proxy_set_header X-Real-IP \$remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 60s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /actuator/ {
|
||||||
|
proxy_pass http://tenant-service:9001/actuator/;
|
||||||
|
proxy_set_header Host \$host;
|
||||||
|
proxy_set_header X-Real-IP \$remote_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /file/ {
|
||||||
|
proxy_pass http://file-service:8086/file/;
|
||||||
|
proxy_set_header Host \$host;
|
||||||
|
proxy_set_header X-Real-IP \$remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||||
|
client_max_body_size 500m;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
proxy_send_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /docs/ {
|
||||||
|
proxy_pass http://tenant-web:80/docs/;
|
||||||
|
proxy_set_header Host \$host;
|
||||||
|
proxy_set_header X-Real-IP \$remote_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /ops {
|
||||||
|
proxy_pass http://ops-web:80;
|
||||||
|
proxy_set_header Host \$host;
|
||||||
|
proxy_set_header X-Real-IP \$remote_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://tenant-web:80;
|
||||||
|
proxy_set_header Host \$host;
|
||||||
|
proxy_set_header X-Real-IP \$remote_addr;
|
||||||
|
proxy_set_header Accept-Encoding "";
|
||||||
|
sub_filter 'wss://im.dev.xuqinmin.com/ws/im' 'wss://\$host/ws/im';
|
||||||
|
sub_filter 'https://dev.xuqinmin.com' 'https://\$host';
|
||||||
|
sub_filter_once off;
|
||||||
|
sub_filter_types text/javascript application/javascript;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NGINX_CONF
|
||||||
|
ok "nginx HTTPS 配置已生成(${DEPLOY_DOMAIN})"
|
||||||
|
|
||||||
|
# docker-compose override:挂载 /etc/letsencrypt 到 nginx 容器
|
||||||
|
cat > "$ROOT_DIR/docker-compose.override.yml" << 'OVERRIDE_YAML'
|
||||||
|
# 由 deploy.sh 自动生成 — HTTPS 模式需要挂载 Let's Encrypt 证书
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
volumes:
|
||||||
|
- /etc/letsencrypt:/etc/letsencrypt:ro
|
||||||
|
OVERRIDE_YAML
|
||||||
|
ok "docker-compose.override.yml 已生成(SSL 证书挂载)"
|
||||||
|
|
||||||
|
else
|
||||||
|
ok "config/nginx/conf.d/xuqm.conf 就绪(HTTP 模式,使用仓库内文件)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# (以下 heredoc 为静态配置的备份注释,不执行)
|
||||||
: <<'NGINX_CONF'
|
: <<'NGINX_CONF'
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# XuqmGroup 私有化部署 — Nginx 路由配置
|
# XuqmGroup 私有化部署 — Nginx 路由配置
|
||||||
@ -474,8 +692,6 @@ server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
NGINX_CONF
|
NGINX_CONF
|
||||||
# 实际使用仓库中的文件(已跳过上方 heredoc)
|
|
||||||
ok "config/nginx/conf.d/xuqm.conf 就绪(使用仓库内文件)"
|
|
||||||
|
|
||||||
# config/vendors/push.env — 推送服务厂商凭据(初始为关闭状态,按需开启)
|
# config/vendors/push.env — 推送服务厂商凭据(初始为关闭状态,按需开启)
|
||||||
mkdir -p "$ROOT_DIR/config/vendors"
|
mkdir -p "$ROOT_DIR/config/vendors"
|
||||||
@ -528,7 +744,7 @@ cat > "$ROOT_DIR/config/sdk/xuqm-private-sdk.json" <<EOF
|
|||||||
"controlBaseUrl": "${CONSOLE_BASE}",
|
"controlBaseUrl": "${CONSOLE_BASE}",
|
||||||
"fileBaseUrl": "${CONSOLE_BASE}",
|
"fileBaseUrl": "${CONSOLE_BASE}",
|
||||||
"imApiBaseUrl": "${CONSOLE_BASE}",
|
"imApiBaseUrl": "${CONSOLE_BASE}",
|
||||||
"imWsUrl": "ws://${DEPLOY_HOST}",
|
"imWsUrl": "${_WS_SCHEME}://${DEPLOY_HOST}/ws/im",
|
||||||
"features": {
|
"features": {
|
||||||
"file": true,
|
"file": true,
|
||||||
"im": true,
|
"im": true,
|
||||||
|
|||||||
正在加载...
在新工单中引用
屏蔽一个用户