上周有个前端同事问我:本地项目怎么安全发给客户预览?我当时愣了一下,因为这是一个看起来基础,但实际很多人会绕远路的问题。不少开发者一听到“预览”,第一反应就是“部署”:买服务器、装 Nginx、配域名、搞备案,最后把前端资源放上去。为了一个五分钟的演示,把一个本来只需要一个链接的事情,硬生生做成了一个小型运维项目。
这里真正的矛盾在于:预览和部署根本不是一回事。预览只要求客户在短时间内看到效果,部署才要求在公网稳定承载业务。如果你总是把预览当成部署来做,就会在不必要的事情上花掉大量时间。反过来,如果你只把它当预览,不考虑路径和数据安全,也容易在交付时翻车。
这篇文章会从最小负担的方案讲起,一步步拆到需要后端和数据库的情况。核心判断只有一个:发给客户预览,不一定要部署服务器,但一定要先搞清楚项目类型、客户位置和数据边界,再选一条最短通路。
1. 先搞清楚一件事:预览不是部署,是一次“可控暴露”
1.1 预览和部署的三个本质差异
很多人以为“给客户预览”和“上线部署”只是规模上的差别。实际差别不是规模,而是目标不同。
部署的目标是让系统持续可用。它必须考虑并发、日志、监控、备份、故障恢复,需要稳定的公网环境、域名、证书和足够的资源。对一个正经业务来说,这些都是底线。
预览的目标是让客户在特定时间窗口内看到效果。它不需要 7×24 小时在线,不需要复杂监控,也不需要完整运维体系。它要的是快速、可控、不泄露不该暴露的东西。所以预览更像是一次“可控暴露”,而不是一次“正式放量”。
差异会直接决定方案选择。如果你要长期线上运行,那就必须用云服务器或 PaaS 平台。如果你只是给客户看效果,完全可以用静态文件、局域网、公网映射、托管平台这些轻量手段。把这两个目标混在一起,才会出现“为了演示一个页面,买了一台云服务器,结果一个月只开机两次”的情况。
在工程经验里,判断一个需求到底是预览还是部署,只需要看两个问题:
- 客户使用这个环境是为了“看看”,还是为了“日常用”?
- 这个环境是否需要保留一个月以上?
只要答案是“看看”和“不需要”,那就不该按生产部署的标准去做。
1.2 先回答四个问题,再决定用哪条路
与其先找工具,不如先做判断。我一般会按下面四个问题筛选方案:
- 客户在现场吗?
- 项目是纯前端,还是带后端和数据库?
- 项目更新频率高不高?
- 数据敏感吗?
这四个问题能直接帮你排除掉一大半不合适的方案。
客户在现场,就用局域网访问。客户在外地,就要公网映射或托管平台。项目是纯前端,甚至可以打包发文件。项目带后端,就要考虑隔离演示环境。数据敏感,就不能拿公网映射工具随便转发。更新频繁,就尽量走自动构建,别每次手动打包发压缩包。
这个筛选过程看起来简单,但能避免很多返工。我见过有人为了让客户远程看一个纯 HTML 页面,专门去研究反向代理配置,最后才意识到其实只需要把 index.html 发给客户。不是工具不够好,而是没有先判断需求。
2. 纯静态项目:最快路径是直接把构建产物交给客户
2.1 为什么静态项目根本不需要服务器
如果你的项目是纯 HTML、CSS、JavaScript,没有后端接口,那它本质上就是一组静态文件。浏览器可以直接打开 index.html 运行,不需要任何服务器进程。
很多新手会被开发服务器误导。用 Vite、Webpack 开发时,跑的是npm run dev,地址是localhost:5173。这个开发服务器是为了热更新和调试,不是项目运行的必要条件。构建完成后,dist目录里就是可以独立运行的静态资源。
所以对于纯静态项目,最快的预览方式不是找服务器,而是把构建产物发给客户。
具体做法一般是:
npm run build构建完成后,把dist目录里的文件压缩成一个 zip,发给客户。客户解压后,双击index.html,就能在浏览器里看到效果。
这里有个关键点:发给客户前,先自己在本地确认一遍dist目录可以直接打开,而不是打开一下又跑回去开发服务器。因为开发环境看到的页面效果,和静态文件直接打开的效果,可能存在路径或资源加载差异。
2.2 打包后发给客户,最容易踩的坑是路径和拦截
纯静态文件方案简单,但有三个坑很常见。
第一个坑是路径。
构建工具默认生成的资源路径是绝对路径,比如/assets/index.js。在本地开发服务器访问没问题,但如果客户直接双击index.html,浏览器会按本地文件路径去找/assets/...,结果大概率是 404,页面白屏。
解决办法是在构建配置里把基础路径改成相对路径。以 Vite 为例:
export default { base: './' }改完之后重新构建,dist/index.html里的资源路径就会变成相对路径,客户不管在哪里打开,都能正确找到样式和脚本。
第二个坑是浏览器拦截。
搜索热词里有一个很典型的报错:“你尝试预览的文件可能对你的计算机有害。如果你信任此文件以及其来源,请打开此文”。这个提示经常出现在从聊天工具接收 HTML 文件时。它并不是说文件真的有病毒,而是浏览器或系统对本地文件的保护机制。
解决办法也很简单:让客户优先使用 Chrome 或 Edge 打开,不要用某些压缩软件的“预览”功能直接看 HTML。如果用的是微信自带的文件预览,看到的是文本内容而不是页面效果,那就要求客户选择“用其他应用打开”,并指定浏览器。
第三个坑是 PDF 或特殊格式无法预览。
如果发给客户的只是单个 HTML 页面,里面嵌入了 PDF,有的浏览器会因为本地文件限制,拒绝加载 iframe 里的 PDF。遇到这种情况,可以建议客户右键点击 PDF 链接,选择“在新标签页中打开”,或者把整个预览环境放到公网环境里,让浏览器按网络资源处理,而不是本地文件。
静态文件方案也有明确边界:它只适合不需要后端、不需要数据库、不涉及登录态的项目。如果你的项目要调接口,直接发 HTML 给客户,客户看到的只是空壳界面。
3. 客户在现场:局域网访问是最省心的方式
3.1 用开发服务器绑定局域网地址
客户来公司或就在同一栋楼时,没必要把项目发到公网,局域网访问是最快的。
开发服务器默认只监听localhost,所以外部设备访问不到。你需要在启动时让它监听0.0.0.0,或者设置为局域网可见。
以 Vite 为例,最简单的配置是在vite.config.js里设置:
export default { server: { host: true } }这样启动后,终端会额外显示一个Network: http://192.168.x.x:5173的地址。手机或客户电脑连上同一个 WiFi,在浏览器输入这个地址,就能直接访问项目。
如果你的项目已经构建完,也可以不启动开发服务器,用简单的静态服务把dist目录暴露到局域网:
npx serve dist它会启动一个本地静态服务,并显示局域网访问地址。这个方式比开发服务器更接近生产构建,也更稳定。
3.2 局域网预览的边界:一个坑比一个坑深
局域网方案看起来简单,但有两个常见问题。
第一个是 AP 隔离。
很多公司、酒店、咖啡厅的 WiFi 都会开启 AP 隔离,设备之间互相不能访问。也就是你手机能上网,但访问不了同事电脑上的192.168.x.x:5173。这个问题在办公网络里尤其常见。解决办法是如果客户在现场,优先安排一个独立的小路由器,或者使用手机热点。
手机热点会形成一个小局域网,所有连上这台手机的设备可以互通。我经常用这个方式做现场演示,简单、稳定、不依赖公司网络策略。
第二个是防火墙。
Windows 和 macOS 默认会拦截外来端口访问。启动服务后,如果同一局域网的其他设备无法访问,大概率是系统防火墙拦截了对应端口。Windows 上需要在“高级安全 Windows Defender 防火墙”中添加入站规则,或者临时允许 Node.js 通过防火墙。
如果客户电脑上装了不少安全软件,还会出现二次拦截。遇到“无法访问此网站”,建议先在局域网内的另一台设备上测试。如果其他设备能访问,只有客户电脑不能访问,问题通常出在客户电脑的网络安全策略上。
局域网方案的边界很明确:客户必须和你在同一网络。客户异地、跨城市、跨公司时,这个方案完全失效。
4. 客户在外地:临时公网映射如何做到“用完即走”
4.1 原理:一个本地服务,一个公网地址
客户不在同一网络,这是远程预览最常见的场景。解决思路也简单:把本地服务的某个端口,临时映射成一个公网地址。
原理上,本地项目仍然在你自己机器上跑,比如127.0.0.1:5173。然后运行一个公网映射工具,它会在远端给你分配一个 HTTPS 地址。客户访问这个 HTTPS 地址时,请求会被转发到你本地的 5173 端口。
这样一来,你不需要买公网服务器,不需要装 Nginx,也不需要备案域名。整个映射过程像一个临时通道,用完就可以关闭。
这类工具通常免费版就够用:一般会分配一个随机域名,有效期从几分钟到几小时不等,足够一次演示。
4.2 一个安全且克制的映射预览流程
公网映射虽然方便,但它把本地服务暴露给了外部网络。使用时要遵循一套相对克制的流程。
第一步,在本地把项目跑起来,先用127.0.0.1确认服务正常。这里的正常不只是页面能打开,还包括接口、样式、图片都不报错。如果本地都有问题,映射出去只会把问题放大。
第二步,启动映射工具,只映射项目本身的端口。千万不要顺手把数据库管理后台、开发工具端口也一起映射出去。本地项目里如果配置了数据库连接、Redis 密码、API 密钥,在映射前先从配置里移除或改掉。
第三步,映射工具会生成一个公网地址。先用手机流量访问一遍,确认可以正常打开。注意手机流量和公司网络不是同一网络,能比较真实地模拟客户访问环境。
第四步,把链接发给客户时,顺手附上访问期限和交互说明。比如“这个链接是临时预览地址,仅用于今天演示,请勿分享给其他人”。
第五步,演示结束后,立刻关闭映射进程。不要让它一直挂在后台,否则本地服务和端口会一直暴露着。
4.3 为什么不能把它当成生产环境
公网映射天然适合临时预览,但不适合任何意义上的“正式使用”。
第一个原因是稳定性。免费版通常带宽很低,图片多、资源大的项目会加载很慢。如果客户的网络环境不佳,很可能打开后白屏或卡顿。本地机器一旦休眠、断网、电源断开,客户访问也会立刻失败。
第二个原因是安全性。在映射场景里,请求会通过第三方中转。如果项目里涉及客户数据、内部业务信息,就不应该走这条路。数据安全优先级高于演示便利。
第三个原因是地址不固定。每次启动映射,生成的地址都可能变化。如果客户想明天再看,链接可能已经失效,又要重新生成,体验很差。
所以公网映射适合“演示一次”和“临时反馈”,不适合需要反复回访、长期保存内容的项目。如果客户会多次访问,建议用托管平台。
5. 想长期反复预览:把项目推到托管平台生成预览链接
5.1 静态托管平台是“不用服务器”的长期版本
如果客户要在一个项目上反复查看、提反馈,你需要一个稳定的链接,而不希望每次启动电脑、每次映射端口。这时候,静态托管平台是更好选择。
这类平台的特点是:你把代码推到 Git 仓库,平台自己拉代码、安装依赖、执行构建、生成一个固定的公网访问地址。你不需要维护任何服务器。
整个流程通常是这样:
- 在本地初始化 Git 仓库,推送代码到远程仓库。
- 在托管平台里选择你的仓库并配置构建命令。
- 平台自动执行
npm install和npm run build。 - 构建成功后,生成一个固定 URL。
- 以后每次往仓库推代码,平台自动重新构建并更新预览链接。
这种方式很适合前端项目。客户拿到的始终是一条稳定的链接,不需要解压文件,也不需要关心本地环境。项目更新后,客户刷新页面就能看到最新效果。
5.2 前端合适,后端不合适
静态托管平台很多时候能解决“不用服务器”的需求,但它有硬边界。
如果项目是纯前端,或者只调用一些公开接口,那静态托管非常合适。如果项目需要后端接口、数据库、文件上传、会话管理,静态托管平台无法直接承载。它们提供的存储和运行环境,面向的是静态资源,不是长期运行的服务。
有的平台也提供函数计算或边缘函数,可以处理轻度后端逻辑,比如表单提交、接口转发、Token 校验。但这个阶段,你已经从“本地预览”跳到了“分布式前端应用”,复杂度会明显上升。如果你只是给客户看一个带交互的界面,没有必要引入。
这里有一个建议:如果项目里包含后端,不要硬塞到静态托管里造假数据,而是考虑把前端放静态托管,后端单独做一个小型演示服务。这是下一节要展开的内容。
6. 带后端或数据库的项目怎么预览
6.1 不要为了演示,把本地数据库和 API 直接暴露到公网
很多人踩过的坑是这样的:本地项目能跑,为了给客户看演示,就把前端口和后端口一起用公网映射暴露出去,然后客户访问时直接操作本地数据库。
这个做法风险很高。
本地数据库通常没有配置访问白名单,也没有做好权限控制。一旦端口被映射到公网,相当于让外部网络直接访问你的开发库。请求稍多、并发稍高,本地机器还可能直接卡死。更糟的是,如果数据库里有客户的真实数据,这种操作已经算安全事故了。
我理解这里的动机:客户想看真实交互,自然希望数据也是真的。但真实数据和演示环境是两回事。正确的做法不是把开发环境原样暴露出去,而是建立一个隔离的演示环境。
6.2 一个稳妥的演示组合:前端静态托管 + 后端容器化 + 独立数据库
当项目必须展示后端能力时,最稳妥的演示组合仍然是“远程部署”,但它不需要你买服务器后手工配置系统。
前端构建产物放到静态托管平台。后端用一个独立的容器镜像,部署到云服务商提供的容器运行环境或轻量 PaaS 平台。数据库单独使用一个演示专用的实例,只对后端的固定公网 IP 或域名开放权限。
虽然这个方案最终还是用到了云资源,但它的目标是建立“演示环境”,不是简单地把本地端口透传到客户面前。好处有三个:
- 本地电脑可以完全关机,客户随时访问。
- 数据库和接口不暴露客户真实数据。
- 演示环境坏了可以一键重建,不影响开发环境。
如果客户后续要长期使用这个演示环境,再考虑升级为正式环境。如果只是看一次效果,用完就可以销毁资源,成本往往比临时买服务器还低。
6.3 如果实在做不到,就做一个“演示模式”
有些人会说:项目太复杂,临时部署后端成本太高,怎么给客户看效果?
这时还可以在项目里加一个“演示模式”。
演示模式的核心不是伪造数据,而是把和真实环境耦合的部分隔离掉。比如:
- 接口请求走 mock 数据,不使用真实数据库。
- 写操作改成内存存储或日志记录,不在数据库里持久化。
- 所有第三方服务调用都屏蔽,避免产生真实订单、真实短信等副作用。
- 项目中保留原有页面结构和交互逻辑,只是数据源替换。
启动时通过环境变量控制:
npm run dev -- --mode demo在 demo 模式下,项目不需要连接数据库,不需要外部服务,可以直接在本机运行,再配合公网映射生成临时地址。客户看到的页面效果是完整的,但背后没有真实业务风险。
这种方式适合给客户看交互、看流程、看设计,不适合看真实数据结果。如果客户的关注点本来就是“这个按钮点了之后,订单会怎么流转”,那 mock 模式可能不够,还是要单独准备一个演示后端。
7. 一条可以长期复用的小项目预览链路
7.1 三步法:构建、选通道、验证
把上面的方案收拢一下,其实可以沉淀成一个固定流程。以后遇到任何“本地项目直接发给客户预览”的需求,都先按这三步走。
第一步,构建。
不要直接拿开发服务器里的效果当预览效果。先执行npm run build,确认产物没有路径问题、资源缺失问题。构建产物是交付物的基本标准。
第二步,选通道。
按客户位置和项目类型选:
| 场景 | 推荐通道 |
|---|---|
| 纯静态项目,客户在场 | 直接发构建产物或局域网访问 |
| 纯静态项目,客户在外地 | 静态托管平台 |
| 带后端项目,客户在场 | 局域网 + 演示模式 |
| 带后端项目,客户在外地 | 前端托管 + 后端容器 / 公网映射临时演示 |
| 数据敏感 | 不要用公网映射,使用隔离的演示环境 |
第三步,验证。
在把链接发给客户之前,先用自己的手机流量访问一遍。这一步能模拟客户的外网访问体验。如果手机都打不开,本地电脑上也大概率还有问题。
7.2 常见问题排查清单
预览时遇到的很多问题,都不是项目代码问题,而是访问路径和环境问题。按下面顺序排查,通常能快速定位。
客户说链接打不开。
先确认本地项目还在运行,没有休眠,没有断网。再确认映射工具或托管平台是否过期。最后用浏览器无痕模式打开,排除缓存和插件问题。
客户打开后页面空白,控制台报资源 404。
大概率是构建路径问题。检查构建配置里的base是否设置为./,或者静态资源是否放在正确目录。
客户收到 HTML 文件后显示代码。
说明 HTML 文件被文本编辑器打开了,或者压缩工具直接预览了源码。让客户改用 Chrome、Edge 浏览器打开 index.html。如果浏览器弹出“文件可能对计算机有害”的提示,选择信任并打开即可。
PDF 或图片在预览里加载不出来。
优先确认是不是本地文件访问受限。如果是 HTML 里嵌了 PDF,建议把整个预览环境放到局域网或公网环境里,让浏览器按网络资源处理。
局域网里手机能访问,客户电脑不能访问。
检查两台设备是否在同一网段,再检查是否开启了 AP 隔离,最后检查系统防火墙是否拦截端口。如果还是不行,切换到手机热点重试。
7.3 什么时候才真的需要一台服务器
最后要把边界说清楚。虽然标题是“不用部署服务器”,但并不是所有场景都适合用轻量方案。
当预览开始变成“试用”,客户要求在里面持续操作、保存数据、查看记录时,这已经不是预览,而是正式试用。试用环境也需要稳定性和数据安全,那就需要正规部署。
当项目包含复杂后端,比如接入支付、消息推送、定时任务、多租户权限时,轻量方案撑不住,云服务器或 PaaS 平台是必然选择。
当团队要快速迭代并保持一个稳定地址时,静态托管加容器化部署,也比本地映射更靠谱。
换句话说,轻量方案解决的是“让客户快速看到效果”的问题,不代表它可以替代生产环境。普通开发者最需要的能力,不是掌握所有部署工具,而是能在不同的需求阶段,判断出到底该用多重的方案。
回到开头那个问题。本地项目直接发给客户预览,本质上不是一道“部署题”,而是一道“选择题”。先判断客户在哪里,再判断项目有没有后端,最后判断数据敏不敏感,你就能从静态文件、局域网、公网映射、托管平台、演示模式里选出一条最短路径。最怕的是,手上只有一把锤子,看到任何前端项目都先想到服务器。先把最小可用预览跑通,再根据客户反馈决定是继续临时演示,还是正式上线,这才是真正节省时间的做法。