Python + Vue3 人脸识别考勤系统本地部署:手机外网打卡与演示怎么打通
标签:Python、Vue.js、人工智能、内网穿透、项目部署
很多 Python + Vue3 的人脸识别考勤项目,在电脑上跑起来不难,真正卡人的地方反而是:手机怎么访问本地页面?摄像头权限怎么调通?临时发给同事验收时,别人不在同一个 Wi-Fi 里怎么办?
这篇不讲数据库面板、监控大屏,也不讲 Home Assistant 那类局域网设备管理。近期这些方向已经写过不少了。今天只聚焦一个更具体的场景:AI 视觉项目本地启动后,用手机外网打开 Vue3 页面,调用 Python 后端接口,完成拍照打卡演示。
文中的项目命令以常见Python 后端 + Vue3 前端结构为例。你的仓库地址、后端入口文件、前端端口需要按实际项目 README 替换;不要直接套不存在的 GitHub 地址。
1 适用场景:本地跑通以后,最缺的是一条外网演示链路
人脸识别考勤系统一般会拆成两部分:
- Python 后端:负责人脸检测、人脸特征提取、考勤记录、接口服务。
- Vue3 前端:负责登录、人员管理、拍照打卡、考勤记录展示。
本地开发时,电脑访问http://127.0.0.1:5173,前端再请求http://127.0.0.1:8000,这条链路很顺。但换成手机后,问题马上出现:手机里的127.0.0.1指的是手机自己,不是你的电脑。
如果只是同一个局域网测试,可以让手机访问电脑内网 IP。比如电脑 IP 是192.168.1.20,手机打开http://192.168.1.20:5173。但临时给同事、老师、客户演示时,对方不在同一网络里,这条路就不够用了。
这时可以用 cpolar 把本地前端页面或后端 API 映射成公网 HTTPS 地址。手机直接打开 HTTPS 链接,浏览器能正常申请摄像头权限,演示链路也更接近真实使用。
这篇的目标很明确:
- 本地启动 Python 后端和 Vue3 前端。
- 检查接口、页面、摄像头权限。
- 用 cpolar 映射前端页面或后端 API。
- 手机外网打开页面,完成拍照打卡测试。
- 演示结束后关闭隧道,避免本地服务长期暴露。
2 环境准备:先把项目拆清楚,再动命令
这里别急着开隧道。AI 视觉项目的问题经常不在外网访问,而在依赖、端口、跨域、摄像头权限这几处。
建议先确认这些环境:
- Python 3.10 或 3.11。
- Node.js 18 及以上。
- npm 或 pnpm。
- 一个可用的摄像头。
- cpolar 客户端。
- 项目里有明确的后端依赖文件,例如
requirements.txt。 - 项目里有明确的前端目录,例如
web/、frontend/或vue3/。
先看项目结构。下面只是常见结构,不要求你的目录完全一样:
face-attendance-demo/ ├── backend/ │ ├── requirements.txt │ ├── app/ │ │ └── main.py │ └── data/ └── frontend/ ├── package.json ├── vite.config.ts └── src/如果你的后端是 Flask,入口文件会换成app.py;如果是 Django,会有manage.py;如果是 FastAPI,常见入口是app/main.py。这一步不是为了纠结框架,而是为了知道后面到底该启动哪个进程。
2.1 安装 cpolar
Linux / 树莓派 / 支持 systemd 的 Linux 可以使用官方一键安装脚本:
curl -L https://www.cpolar.com/static/downloads/install-release-cpolar.sh | sudo bashmacOS 使用 Homebrew 安装:
brew tap probezy/core && brew install cpolar sudo cpolar service install sudo cpolar service start安装后检查本地管理页:
cpolar version curl -s http://127.0.0.1:9200 || echo "cpolar 服务未启动"浏览器打开:
http://127.0.0.1:9200看到 cpolar Web UI 后,登录账号。也可以用命令行写入 token:
cpolar authtoken 你的_cpolar_token提醒一下:临时演示用随机 HTTPS 地址就够了。免费随机公网地址 24 小时内会变化;如果要长期给团队固定访问,固定二级子域名需要基础套餐或以上。
3 本地启动:先确认后端和前端各自能跑
这一步只在电脑本机操作。先把本地链路跑通,再考虑手机访问,不然排错会变成一锅粥。
3.1 启动 Python 后端
进入后端目录,创建虚拟环境并安装依赖:
cd backend python3 -m venv .venv source .venv/bin/activate python -m pip install --upgrade pip pip install -r requirements.txt如果项目 README 指定了 Conda、Poetry 或 uv,就按 README 的方式安装依赖。这里用venv + pip,是因为大多数 Python 示例项目都能按这个思路落地。
FastAPI 项目常见启动命令如下:
uvicorn app.main:app --host 0.0.0.0 --port 8000Flask 项目常见启动命令如下:
flask --app app run --host 0.0.0.0 --port 8000Django 项目常见启动命令如下:
python manage.py runserver 0.0.0.0:8000三种命令选一种,不要同时启动。你的项目 README 写了哪个入口,就用哪个入口。
启动后先测健康接口。项目没有/health接口时,换成 README 里提供的接口地址:
curl http://127.0.0.1:8000/health如果这里没有返回内容,先不要开 cpolar。优先检查后端日志、依赖是否装全、端口是否被占用、模型文件路径是否正确。
3.2 启动 Vue3 前端
进入前端目录安装依赖:
cd ../frontend npm install如果项目使用 pnpm,按下面命令:
pnpm install给前端配置后端 API 地址。Vite 项目常见写法是在前端目录创建.env.development:
cat > .env.development <<'EOF' VITE_API_BASE_URL=http://127.0.0.1:8000 EOF启动前端时建议显式绑定0.0.0.0,后面手机访问和 cpolar 映射都会更省事:
npm run dev -- --host 0.0.0.0 --port 5173如果使用 pnpm:
pnpm dev --host 0.0.0.0 --port 5173打开电脑浏览器访问:
http://127.0.0.1:5173在页面里试一次登录、人员列表、拍照入口。这里重点看两件事:前端页面能不能正常加载,开发者工具 Network 里接口请求是不是打到8000端口。
4 本地检查:摄像头和跨域不要等到手机上再排
人脸识别打卡项目最容易卡在摄像头权限。Chrome、Edge、Safari 对getUserMedia有明确限制:公网访问时要走 HTTPS;本机的localhost属于浏览器认可的安全上下文。
所以本地电脑访问http://127.0.0.1:5173能调起摄像头,不代表手机访问 HTTP 地址也能调起摄像头。后面用 cpolar 的 HTTPS 地址,就是为了解决这个演示场景。
前端拍照组件里常见代码大概是这样:
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false })如果页面没有弹出摄像头授权,先检查:
- 浏览器地址是否为 HTTPS 或 localhost。
- 手机系统是否允许浏览器访问摄像头。
- 页面里是否在用户点击按钮后再调用摄像头。
- 前端控制台是否报
NotAllowedError或NotFoundError。
跨域也要提前处理。FastAPI 可以这样放开开发环境来源:
from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=[ "http://127.0.0.1:5173", "http://localhost:5173" ], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], )外网演示时,前端会换成 cpolar 的 HTTPS 域名。为了临时演示省心,可以在开发环境把allow_origins补上演示域名;演示结束后删掉。别在正式环境长期使用allow_origins=["*"]搭配凭证请求。
5 用 cpolar 打通外网访问:优先映射前端页面
这里推荐先映射 Vue3 前端端口。原因很简单:手机只需要打开一个页面,页面再去调后端接口,体验最接近真实打卡。
前端已经监听5173后,打开一个新终端执行:
cpolar http 5173命令输出里会出现公网地址,HTTP 和 HTTPS 各一条。手机打卡演示优先使用 HTTPS 地址,形如:
https://xxxx.cpolar.top也可以从 Web UI 查看:
http://127.0.0.1:9200路径是“状态 → 在线隧道列表”,复制 HTTPS 公网地址即可。
这里有个小提醒:不要在多个终端里反复执行多个 cpolar 前台隧道命令。官方文档提醒过,同时打开多个前台实例会遇到登录实例限制。需要长期管理多个隧道时,用 Web UI 或配置文件方式更稳。
5.1 后端 API 地址怎么处理
手机打开公网前端页面后,前端不能继续请求http://127.0.0.1:8000。这个地址在手机上仍然指向手机自己。
有两种处理方式。
更省事的方式是让 Vue3 开发服务器代理 API。vite.config.ts示例:
import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], server: { host: '0.0.0.0', port: 5173, proxy: { '/api': { target: 'http://127.0.0.1:8000', changeOrigin: true } } } })前端请求统一写成相对路径:
await fetch('/api/attendance/check-in', { method: 'POST', body: formData })这样手机访问 cpolar 的前端 HTTPS 地址时,接口请求会先打到 Vite,再由 Vite 转给本机 Python 后端。
另一种方式是单独映射后端端口:
cpolar http 8000拿到后端 HTTPS 地址后,把前端环境变量改成:
cat > .env.development <<'EOF' VITE_API_BASE_URL=https://你的后端公网地址 EOF改完要重启前端开发服务器。这个方案适合前后端分开演示,但要额外处理后端 CORS 白名单。
6 手机外网验证:别只看页面打开,要真的拍一次
手机关闭 Wi-Fi,使用移动网络打开 cpolar 生成的 HTTPS 前端地址。这样可以确认它不是靠局域网访问成功的。
按下面顺序验收:
- 页面能打开,首屏资源加载完整。
- 登录或进入打卡页没有接口报错。
- 点击拍照按钮,浏览器弹出摄像头授权。
- 授权后能看到实时画面。
- 点击打卡,后端日志出现识别请求。
- 页面显示打卡结果,后台能看到考勤记录。
这一步不是为了走形式,而是确认三条链路都通了:公网页面访问、手机摄像头权限、前端到后端接口。
如果页面能打开但接口失败,先看前端 Network:
- 请求地址是不是还停留在
127.0.0.1:8000。 - 请求是否走了
/api代理。 - 后端控制台有没有收到请求。
- FastAPI / Flask / Django 的 CORS 配置是否包含当前 HTTPS 域名。
如果摄像头没有弹窗,先检查手机浏览器权限。iPhone 上可以到系统设置里检查 Safari 或当前浏览器的相机权限;Android 机型也要确认浏览器应用本身拿到了摄像头权限。
7 常见问题:这几个坑最耽误时间
7.1 手机打开页面白屏
先在电脑上用无痕窗口打开 cpolar 的 HTTPS 地址。电脑也白屏,就看前端终端日志和浏览器控制台。
常见检查项:
curl -I http://127.0.0.1:5173如果本地5173都没有响应,说明 Vue3 开发服务没启动或端口变了。重新执行:
npm run dev -- --host 0.0.0.0 --port 51737.2 接口报 CORS
前端页面域名变成 cpolar HTTPS 后,后端看到的是一个新的 Origin。开发环境可以把这个 HTTPS 域名加入白名单。
FastAPI 示例:
allow_origins=[ "http://127.0.0.1:5173", "http://localhost:5173", "https://你的前端公网地址" ]改完后重启 Python 后端。只改代码不重启,接口仍然按旧配置运行。
7.3 人脸识别接口慢
人脸检测、特征提取依赖 CPU、模型大小和图片尺寸。演示时别一上来上传超大照片,先用手机实时拍一张普通清晰度图片测试。
如果接口耗时长,优先看后端日志里每一步耗时。可以临时加简单计时:
import time start = time.time() # 这里执行人脸检测或特征提取 print(f"face pipeline cost: {time.time() - start:.2f}s")演示场景追求链路打通,不要同时打开太多模型、太多摄像头预览、太多调试窗口。这里先只测 1 个打卡账号,排错会轻很多。
7.4 cpolar 地址打不开
按这条顺序查,不要一上来重装:
curl -I http://127.0.0.1:5173 curl -s http://127.0.0.1:9200 || echo "cpolar Web UI 未响应"如果本地前端正常,再去 cpolar Web UI 的“状态 → 在线隧道列表”确认隧道在线。公网地址要复制完整 HTTPS 链接,少一个字符都会打不开。
7.5 免费随机地址变了
免费套餐生成的是随机临时地址,24 小时内会变化。临时演示前重新复制一次在线隧道地址,发给同事或老师即可。
如果演示材料里要写固定链接,使用固定二级子域名。固定二级子域名需要基础套餐或以上;自定义域名需要专业套餐或以上。
8 安全边界:演示可以外放,管理能力别裸奔
人脸识别考勤系统涉及人员信息、照片、人脸特征和打卡记录。临时演示可以开公网入口,但不要把开发环境长期裸露在公网。
建议至少做到这几条:
- 演示账号使用测试数据,不放真实员工照片和隐私信息。
- 后台管理页加登录,不要把默认账号密码写在页面上。
- 后端调试接口不要返回人脸特征向量、文件绝对路径和异常堆栈。
- cpolar 隧道只在演示期间开启,演示结束立即关闭。
- CORS 白名单只放本地地址和演示域名,结束后移除临时域名。
- 不把数据库、Redis、SSH 端口直接作为默认公网演示入口。
这不是保守,是省事。临时验收最怕的不是链路没通,而是演示完忘了关,开发接口继续暴露在公网。
9 收尾关闭隧道:演示结束别忘了清场
如果你是用前台命令启动的:
cpolar http 5173演示结束后,在对应终端按:
Ctrl + C再打开 cpolar Web UI 检查在线隧道列表,确认前端隧道已经下线:
http://127.0.0.1:9200如果你是通过 Web UI 创建的隧道,进入隧道列表停用或删除对应隧道。需要继续本地开发时,Python 后端和 Vue3 前端可以保留;不需要继续调试时,把两个服务也关掉。
# 在后端终端按 Ctrl + C # 在前端终端按 Ctrl + C临时写入的 cpolar 演示域名也要从后端 CORS 白名单里删掉。这里别偷懒,删掉后重启一次后端,确保配置已经恢复到本地开发状态。
10 总结
到这里,一个常见的 Python + Vue3 人脸识别考勤系统就完成了本地部署、外网演示和手机摄像头联调。电脑负责跑 Python 后端和 Vue3 前端,cpolar 负责把本地页面变成公网 HTTPS 地址,手机负责完成真实拍照打卡验证。
关键步骤就三件事:
- 先本地跑通:后端
8000、前端5173、页面和接口都要能在电脑上访问。 - 再外网映射:优先用
cpolar http 5173映射前端页面,接口用 Vite 代理转到本地后端。 - 手机实测验收:关闭 Wi-Fi,用移动网络打开 HTTPS 地址,完成授权、拍照、识别、打卡记录检查。
如果只是给同事临时验收,随机 HTTPS 地址已经够用;如果要固定给团队使用,再考虑固定二级子域名和更严格的鉴权。AI 视觉项目的演示重点不是把服务长期挂出去,而是把“页面能打开、摄像头能授权、接口能识别、记录能落库”这条链路清清楚楚地跑完。