当前位置: 首页 > news >正文

零基础联通云部署实战:三维编辑器上云全记录

前言:作为一个只写过前端代码、从未接触过服务器部署的开发者,当我第一次需要把本地的三维编辑器(支持爆炸图编辑、三维组态、设备空间分析)部署到联通云服务器上时,面对"Docker"、"容器"、"安全上下文"这些概念完全是懵的。这篇文章记录了我从零开始,把项目成功部署到云端的完整过程,以及踩过的那些让人抓狂的坑。

一、项目架构与部署全景图

在深入代码前,我们先建立整体认知。我们的三维编辑器系统包含这些部分:

关键概念:我们并不是直接把代码"放"到服务器上运行,而是使用Docker创建一个"集装箱"(容器),在里面配置好所有运行环境,然后把集装箱放到服务器上。


二、核心文件详解:每个文件都在做什么?

1. Dockerfile —— 集装箱的"装修图纸"

这个文件告诉 Docker:"我要创建一个包含 Apache、PHP 和各种配置的镜像"。逐行解释:

# 基于官方 PHP 8.2 + Apache 镜像(就像选择毛坯房户型) FROM php:8.2-apache # 安装系统依赖:zip 扩展(用于文件压缩上传) RUN apt-get update && apt-get install -y \ libzip-dev zip unzip \ && docker-php-ext-install zip \ && rm -rf /var/lib/apt/lists/* # 清理缓存,减小镜像体积 # 启用 Apache 的四个关键模块: # rewrite: URL 重写(支持前端路由) # headers: HTTP 头管理(CORS 跨域需要) # mime: 文件类型识别(确保 .js 被识别为 JS 而非文本) # deflate: Gzip 压缩(让 5MB 的 JS 文件传输更快) RUN a2enmod rewrite headers mime deflate # --- Apache 站点配置(核心!)--- # 这里使用 HERE 文档(<<'APACHECONF')批量写入配置文件 RUN cat > /etc/apache2/sites-available/000-default.conf <<'APACHECONF' <VirtualHost *:80> DocumentRoot /var/www/html # 网站根目录 DirectoryIndex cc_editor.html # 默认首页 # 大文件传输超时设置(我们的 JS 有 5MB+) Timeout 300 KeepAlive On <Directory /var/www/html> AllowOverride All # 允许 .htaccess 覆盖配置 Require all granted # 允许所有 IP 访问 # --- MIME 类型修复(坑点!)--- # 确保浏览器知道 .js 是脚本,.babylon 是 JSON AddType application/javascript .js .mjs AddType application/json .json .babylon # --- 跨域支持(CORS)--- # 允许任何域名调用我们的 API(开发阶段方便) Header set Access-Control-Allow-Origin "*" # --- Gzip 压缩(性能优化)--- <IfModule mod_deflate.c> AddOutputFilterByType DEFLATE application/javascript DeflateCompressionLevel 6 # 压缩级别 1-9,6 是平衡值 </IfModule> </Directory> </VirtualHost> APACHECONF # --- PHP 配置调整 --- # 解决上传文件大小限制(默认只有 2M,我们改成 200M 支持模型上传) RUN cat > /usr/local/etc/php/conf.d/custom.ini <<'PHPINI' upload_max_filesize = 200M post_max_size = 200M max_execution_time = 300 # 脚本最长运行时间(秒) memory_limit = 256M # PHP 可用内存 PHPINI # 复制当前目录所有文件到容器的 /var/www/html(网站根目录) WORKDIR /var/www/html COPY . /var/www/html/ # 设置文件权限(Linux 权限管理) # www-data 是 Apache 的默认用户,必须让他有读写权限 RUN chown -R www-data:www-data /var/www/html \ && find /var/www/html -type d -exec chmod 755 {} \; \ && find /var/www/html -type f -exec chmod 644 {} \; \ && chmod -R 775 /var/www/html/Resources # 资源目录需要写入权限 # 暴露 80 端口(HTTP 默认端口) EXPOSE 80 CMD ["apache2-foreground"] # 容器启动时运行 Apache

2. deploy.sh —— 一键部署脚本(重点详解)

这是我最困惑又最重要的文件。逐行解释:

#!/bin/bash # 上面这行叫 Shebang,告诉系统用 /bin/bash 执行此脚本 # set -e 表示:如果任何命令执行失败(返回非0),立即停止脚本 # 防止"带病"继续执行,造成更难排查的问题 set -e # 定义变量(避免重复写,方便修改) IMAGE_NAME="cc_dist" # Docker 镜像名称(类似类名) CONTAINER_NAME="cc_dist_app" # 容器实例名称(类似对象名) HOST_PORT=30513 # 服务器对外端口(用户访问用) CONTAINER_PORT=80 # 容器内部端口(Apache 监听) # cd "$(dirname "$0")" 是"进入脚本所在目录"的安全写法 # $0 是脚本本身路径,dirname 取目录,解决"在哪里执行脚本"的路径问题 cd "$(dirname "$0")" # 定义 start 函数(封装启动逻辑) start() { echo "正在构建镜像 ${IMAGE_NAME}..." # docker build -t 标签 . 表示用当前目录 Dockerfile 构建镜像 # . 是构建上下文(COPY 命令会复制这个目录的文件) docker build -t "${IMAGE_NAME}" . # 检查是否已有同名容器在运行 # docker ps -a 列出所有容器(包括停止的) # --format '{{.Names}}' 只输出名字 # grep -q 安静模式匹配,匹配到返回0(真) if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then echo "已存在容器 ${CONTAINER_NAME},先删除..." # 2>/dev/null 把错误输出扔掉(比如容器不存在时的报错) # || true 确保即使删除失败,脚本也不停止(set -e 会杀掉脚本) docker rm -f "${CONTAINER_NAME}" 2>/dev/null || true fi echo "正在启动容器,映射端口 ${HOST_PORT} -> ${CONTAINER_PORT}..." # docker run -d 后台运行(daemon) # --name 给容器起名字,方便后续管理 # -p 端口映射(主机端口:容器端口) docker run -d \ --name "${CONTAINER_NAME}" \ -p "${HOST_PORT}:${CONTAINER_PORT}" \ "${IMAGE_NAME}" echo "启动完成。访问: http://<服务器IP>:${HOST_PORT}" } # 定义 stop 函数(优雅停机) stop() { if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then echo "正在停止并删除容器..." docker stop "${CONTAINER_NAME}" 2>/dev/null || true # 先停止进程 docker rm "${CONTAINER_NAME}" 2>/dev/null || true # 再删除容器 echo "已停止。" else echo "容器不存在,无需停止。" fi } # case 语句处理命令行参数($1 是第一个参数) case "${1:-}" in # ${1:-} 表示如果 $1 未定义,用空字符串 start) start # 调用上面定义的 start 函数 ;; stop) stop ;; *) # * 通配符,匹配任何其他输入 echo "用法: $0 {start|stop}" echo " start - 构建并启动" echo " stop - 停止服务" exit 1 # 返回错误码 ;; esac

使用方式

# 赋予执行权限(第一次使用需要) chmod +x deploy.sh # 启动服务 ./deploy.sh start # 停止服务 ./deploy.sh stop

3. file_manager.php —— 资源管理的大脑

这是一个API 接口文件,供前端 Vue 调用,实现类似"资源管理器"的功能:

  • get-tree: 获取目录树(左侧文件树展示)

  • get-files: 获取文件列表(带过滤,比如只看 .glb 模型)

  • upload-file: 上传模型/贴图(支持大文件)

  • delete-file: 删除资源

  • get-text-file-content: 读取场景配置文件(.e3d/.c3d)

安全设计

  • validatePath()函数防止目录遍历攻击(比如传入../../../etc/passwd试图读取系统文件)

  • 限制BASE_DIR/Resources目录,所有操作只能在这个"沙盒"内进行

  • 白名单校验文件后缀(只允许jpg/png/glb/gltf等)

4. diag.html —— 部署诊断神器

部署时如果页面白屏,打开这个文件能看到:

  • Environment: 是否安全上下文、WebGL 支持、UUID 可用性

  • Critical Files: 检查核心 JS 文件是否正确加载(大小检测防止传输损坏)

  • Resource Directories: 测试 PHP 接口是否连通

  • External CDN: 检查能否访问腾讯图标库(内网环境往往不通)


三、Docker 到底是什么?为什么要用它?

通俗理解

想象你要搬家(部署应用):

  • 传统方式:把家具(代码)搬到新家(服务器),然后现场组装家具、接水管、接电线(安装 Apache、PHP、配置环境)。每次搬家都要重新组装,而且新家的螺丝孔位可能不一样(服务器系统差异)。

  • Docker 方式:把整个装修好的房子(容器)连地基一起拔起来,用吊车运到新家,接通水电(端口映射)即可入住。

技术定义

Docker 使用容器化技术,将应用及其依赖(操作系统、Web 服务器、运行时)打包成一个镜像(Image)。镜像运行时成为容器(Container)

核心优势

  1. 环境一致性:本地开发的容器,放到联通云上一模一样,不会出现"我本地明明是好的"这种问题

  2. 隔离性:容器内的 PHP 崩溃不会影响服务器上的其他服务(如 MySQL)

  3. 轻量级:不像虚拟机需要完整操作系统,容器共享主机内核,启动秒级

部署流程图解

本地开发 → 构建镜像(docker build)→ 保存/传输 → 联通云服务器 ↓ 用户浏览器 ← 端口映射(30513)← 运行容器(docker run)← 加载镜像

四、踩坑实录:那些让人崩溃的问题

坑 1:crypto.randomUUID 在云端失效

现象

  • 本地http://localhost:8080运行完美

  • 部署到联通云http://125.34.90.250:30513后,页面白屏,控制台报错:crypto.randomUUID is not a function

原因:浏览器安全上下文(Secure Context)

浏览器规定:

  • localhost/127.0.0.1永远信任,所有高级 API(如 crypto、摄像头、地理位置)可用

  • 192.168.x.x(内网 IP)或公网 IP:不信任,必须使用 HTTPS 才能使用 crypto API

解决方案(Polyfill 降级)

在页面<head>最顶部插入这段代码:

<script> // 如果浏览器不支持 randomUUID(非安全上下文),手动实现一个 if (typeof crypto.randomUUID !== "function") { crypto.randomUUID = function() { // 使用 crypto.getRandomValues(这个 API 在任何环境都可用) // 生成符合 RFC4122 标准的 UUID v4 return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, function(c) { return (+c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> +c / 4).toString(16); }); }; } </script>

原理crypto.getRandomValues不受安全上下文限制,我们用它生成随机数,手动拼接成 UUID 格式,保证在低版本浏览器或非 HTTPS 环境下也能生成唯一 ID。

坑 2:TDesign 图标显示为方框或空白

现象:按钮、菜单的图标不显示,但文字正常。

原因:TDesign 默认使用图标字体(Icon Font),通过https://tdesign.gtimg.com/...CDN 加载。联通云服务器如果是内网环境防火墙限制,无法访问腾讯 CDN,导致字体加载失败。

两种写法的区别

写法 A(字符串方式 - 原写法)

<t-icon :name="visible ? 'chevron-left' : 'chevron-right'" />
  • 原理:组件内部根据字符串name动态生成<i class="t-icon-chevron-left">,依赖 CSS 字体文件中的矢量图标

  • 问题:CSS 里定义了@font-face { src: url(https://tdesign.gtimg.com/...),CDN 失效则图标失效

写法 B(组件方式 - 解决方案)

<script setup> import { ChevronLeftIcon, ChevronRightIcon } from 'tdesign-icons-vue-next'; </script> <template> <component :is="visible ? ChevronLeftIcon : ChevronRightIcon" /> </template>
  • 原理:直接引入** SVG 组件**,图标作为 Vue 组件编译进项目,不依赖外部 CDN

  • 优势:离线可用,首屏渲染更快(不额外请求字体文件)

建议:内网/政企项目永远使用写法 B,避免外部依赖。

坑 3:localhost 能访问,IP 地址访问失败

现象

  • http://localhost/cc_dist/cc_editor.html:WebGL 正常,UUID 正常,功能完整

  • http://192.168.90.227/cc_dist/cc_editor.html:UUID 报错,某些 API 被禁用

原因:同样是Secure Context策略。浏览器将localhost视为安全开发环境,给予特权;而任何 IP 地址(包括内网 IP)被视为潜在风险环境,限制敏感 API。

完整权限对比表

表格

访问方式Secure Contextcrypto.randomUUIDWebGL摄像头
http://localhost✅ 是✅ 可用
http://192.168.x.x❌ 否❌ 禁用
http://公网IP❌ 否❌ 禁用
https://任意✅ 是✅ 可用

启示:生产环境务必配置 HTTPS(即使使用自签名证书),否则现代 Web API 功能受限。


五、完整部署流程总结

如果你是第一次部署,按这个顺序操作:

# 1. 本地构建前端(确保生成 dist 目录) npm run build # 2. 将构建产物上传到联通云服务器(使用 scp 或 FTP) scp -r dist/* root@125.34.90.250:/data/yuzhexu/cc_dist/ # 3. SSH 登录服务器 ssh root@125.34.90.250 cd /data/yuzhexu/cc_dist # 4. 执行部署(使用我们详解过的脚本) ./deploy.sh start # 5. 验证部署 # 浏览器访问:http://125.34.90.250:30513/diag.html # 确认所有检查项为 OK # 6. 正式使用 # 访问:http://125.34.90.250:30513/cc_editor.html

六、结语:给新手的建议

  1. Docker 不是魔法:它只是把"配置环境"这个步骤提前到本地,确保"一次构建,到处运行"。理解容器 = 进程 + 文件系统隔离,就不再有神秘感。

  2. 浏览器安全策略是道坎localhostIP 地址的差异、HTTPHTTPS的差异,不是 Bug,是浏览器的安全设计。开发时可以用localhost,上线后必须规划 HTTPS。

  3. 离线优先:如果你的系统在专网/内网运行(如煤矿井下系统),永远不要依赖外部 CDN(字体、图标、JS 库),全部使用本地资源或 npm 包引入。

  4. 诊断工具先行:像diag.html这样的诊断页面是部署的"听诊器",先确保基础资源加载、MIME 类型、CORS 配置正确,再排查业务逻辑。

从零到一的部署最难的是理解全流程。希望这篇博客能成为你部署路上的"新手村攻略",祝你的三维编辑器顺利上线!

http://www.jsqmd.com/news/433133/

相关文章:

  • Last Meeting Theory(最后相遇理论)and Soulmate(灵魂伴侣)
  • 基于ssm的学生健康管理系统w4apa20f(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 拆解百度智能运营平台:AI应用架构师能借鉴的4个架构设计理念
  • 从大模型推理边界看职业壁垒:为什么说接入云端大模型API只是人机协作的第一步?
  • YOLO11 改进 - SPPF模块 替代SPPF, Mona多认知视觉适配器(CVPR 2025):打破全参数微调的性能枷锁:即插即用的提点神器
  • 基于ssm家电售后服务管理系统d9x66u24(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 解析大数据领域数据增强的应用场景
  • S001 【模板】从前缀函数到KMP应用 字符串匹配 字符串周期
  • YOLO11 改进 - Mamba _ 集成Mamba-YOLO(AAAI 2025),Mamba-YOLO11-L 替换骨干,破解全局依赖建模难题,实现高效实时检测
  • YOLO11 改进 - Mamba _ 集成Mamba-YOLO(AAAI 2025),Mamba-YOLO11-T 替换骨干,破解全局依赖建模难题,实现高效实时检测
  • 私有部署、安全可控:BeeWorks一体化视频会议解决方案赋能政企高效协同
  • YOLO11 改进 - Mamba _ 集成Mamba-YOLO(AAAI 2025),Mamba-YOLO11-B 替换骨干,破解全局依赖建模难题,实现高效实时检测
  • AWS中东数据中心遭不明物体撞击引发大规模服务中断
  • python核心语法-运算符-类型转换 - 努力-
  • 提示工程远程团队敏捷协作:5个工具让沟通更高效!
  • 问题解决:Oracle VirtualBox创建的虚拟主机不能ping通windows host主机虚拟网卡的ip
  • Qt 捕获应用程序未知异常的方法
  • 异常和自定义错误码使用时机
  • 解读大数据领域结构化数据的性能优化策略
  • YOLO11 改进 - C2PSA _ C2PSA融合Mask Attention掩码注意力,可学习掩码矩阵破解低分辨率特征提取难题 _ 2025 预印
  • 计算资源与AI模型性能提升的关系探讨
  • AI检测会对论文进行误判吗?
  • cf div2 1078 F1
  • 2026城固装修公司排名TOP5权威测评|城固哪家装修公司靠谱?性价比高口碑好首选金匠装饰 - 一个呆呆
  • Python核心语法-Python关键字 - 努力-
  • YOLO11 改进 - C2PSA _ C2PSA融合MSLA多尺度线性注意力(Arxiv2025 ):并行多分支架构融合上下文语义,提升特征判别力
  • 元宵节猜灯谜答题闯关抽奖H5抖音快手微信小程序看广告流量主开源
  • YOLO11 改进 - C2PSA _ C2PSA融合Mona多认知视觉适配器(CVPR 2025):打破全参数微调的性能枷锁:即插即用的提点神器,引领视觉微调新突破
  • react遇坑记
  • 大数据领域存算分离的自动化运维实践