1 项目背景
在很多政务、农业调查、自然资源和离线作业场景中,系统建设往往面临几个很现实的问题:
- 网络环境不稳定,甚至需要完全离线运行。
- 部署环境复杂,不能依赖过多中间件。
- 数据既要可视化展示,又要支持查询、统计、导入导出和授权控制。
- 系统不能太"重",否则维护成本高,现场交付也容易翻车。
基于这些要求,我设计并实现了一套离线土壤数据分析展示系统。这个项目没有走"大而全"的路线,而是采用了非常克制的三层架构:
frontend:浏览器前端backend:FastAPI 后端服务electronend:Electron 桌面离线封装层
整套架构的核心目标只有三个词:
简单、轻量级、安全可控。
2 整体架构概览
从整体上看,这个项目是一个典型的"三段式架构",但和传统互联网系统不同,它更强调离线运行能力和本地资源调度能力。
text
┌───────────────────────────────────────────────┐
│ 用户界面层 │
│ frontend / electron renderer │
│ Vue + Vite + Pinia + Router + Element Plus │
│ Leaflet + ECharts │
└───────────────────────────────────────────────┘
│
┌─────────┴─────────┐
│ │
│ HTTP / API │ IPC
│ │
┌──────────────────────┐ ┌──────────────────────┐
│ backend 服务层 │ │ Electron 主进程层 │
│ FastAPI │ │ main + preload │
│ 路由、鉴权、地图服务 │ │ 文件系统、本地数据库、 │
│ 报表、MBTiles、授权 │ │ 自定义协议、授权生成 │
└──────────────────────┘ └──────────────────────┘
│ │
└─────────┬─────────┘
│
┌─────────────────────────────────┐
│ 本地数据与资源层 │
│ SQLite / MBTiles / GeoJSON │
│ 本地瓦片 / 授权文件 / 媒体资源 │
└─────────────────────────────────┘
可以把它理解成一句话:
Web 前端负责展示,FastAPI 后端负责业务,Electron 负责把整套能力封装成可离线运行的桌面应用。
这个架构不花哨,但非常实用。像工具箱,不像艺术品;关键时刻能干活,这才是工程价值。
3 前端架构:保持足够简单的展示层
frontend 是标准的 Vue 应用,核心职责非常明确:页面展示、地图交互、统计分析、用户操作承载。
- 技术选型
前端采用的技术栈非常克制:
Vue
Vite
Pinia
Vue Router
Element Plus
Leaflet
ECharts
其中地图部分没有上特别重的 GIS 前端框架,而是选择了 Leaflet 这一套偏轻量的方案,再配合 GeoTIFF、Vector Tile 等能力完成专题图层展示。
这类选型有两个好处:
上手快,维护成本低。
体量小,适合离线项目和定制项目快速落地。
- 前端职责边界
前端只做它该做的事:
页面布局与交互
地图展示与专题图层切换
查询结果呈现
统计图表展示
登录态保存
通过统一请求模块调用后端接口
也就是说,前端是一个"干净的 UI 层",并不承担复杂业务逻辑,更不直接碰数据库。
这样的边界划分有一个明显优点:
前端可以专注体验,后端可以专注规则,模块职责不打架。
- 为什么说它简单
前端架构简单,主要体现在三点:
入口清晰,初始化逻辑干净。
请求统一封装,所有 API 调用路径一致。
地图、统计、业务面板都是围绕页面能力组织,而不是把业务逻辑塞进组件里。
简单不是功能少,而是结构不拧巴。
4 后端架构:单体但不臃肿
backend 采用的是 FastAPI,整体设计思路不是"大型微服务化",而是 单体 API 服务 + 清晰模块分层。
这在离线项目里非常合理,因为:
部署简单
运维简单
启动链路短
故障点少
- 后端分层思路
后端整体可以概括为:
controller:接口入口层
service:业务逻辑层
dao:数据访问层
entity:实体/模型层
router:统一路由注册
config:数据库与环境配置
这种结构非常传统,但传统的东西之所以能活这么久,原因很简单:
因为真好用。
- 路由设计
后端通过统一路由管理器注册业务模块,接口分工明确,包括:
要素查询
地图服务
MBTiles 服务
报表服务
行政区划
字典管理
用户与系统配置
一张图业务
公开统计
媒体服务
这种集中式路由注册有个明显优点:
主入口非常干净,新增模块也不会把系统入口搞成一锅粥。
- 数据层为什么轻
这个项目的数据层最值得说的一点,就是它没有为了"看起来高级"而引入一堆复杂基础设施。
核心数据库选用了:
SQLite
这意味着:
不需要额外安装 MySQL/PostgreSQL
部署成本低
迁移方便
离线环境更稳定
对于离线 GIS 系统来说,SQLite 反而是一种非常合适的选择。
尤其是在单机应用、固定数据集、强调快速交付的场景下,它比重量级数据库更"接地气"。
这不是妥协,而是工程判断。
5 Electron 架构:让系统真正具备离线交付能力
如果说 frontend + backend 解决的是"系统能用"的问题,那么 electronend 解决的是"系统能交付、能离线、能落地"的问题。
Electron 这一层不是简单包个壳,而是承担了很多关键职责:
本地窗口管理
本地 SQLite 访问
文件导入导出
本地资源协议分发
授权文件生成
桌面版地图资源调度
- 标准三层结构
Electron 采用了典型的三层设计:
main:主进程
preload:桥接层
renderer:渲染层
这种设计最大的价值是:
把系统能力暴露在一个可控边界内,而不是让前端页面直接拥有 Node 全权限。
- Electron 在本项目中的作用
它并不是替代后端,而是补充后端做不了的事情:
访问本地文件系统
弹出文件选择框
处理本地数据库
直接读取本地瓦片资源
提供桌面级授权能力
为离线地图服务提供协议支持
因此,桌面端并不是"浏览器页面搬进壳子里",而是真正具备本地能力扩展的离线客户端。
- 为什么它依然轻量
很多人一提 Electron 就觉得重,但这个项目里的 Electron 用法其实是非常收敛的:
不搞复杂跨窗口系统
不搞额外的本地服务编排
只暴露必要的 IPC 能力
只处理离线场景中必须落到客户端的那部分功能
换句话说,这里的 Electron 不是"炫技层",而是"实用层"。
6 系统通信链路:边界清晰,路径统一
这个项目的通信方式并不复杂,主要就三条链路:
- 浏览器前端到后端
Vue 页面 -> Axios -> FastAPI API
这是最标准的 Web 通信方式。
前端通过统一请求封装附带 Authorization,后端统一鉴权,中间没有奇怪的绕路,也没有大量重复逻辑。
- Electron 渲染层到主进程
Renderer -> Preload -> IPC -> Main
凡是涉及本地文件、导入导出、授权、SQLite 查询等能力,都通过 IPC 调用主进程完成。
这条链路的价值在于:
把系统能力"白名单化",而不是全部裸露给页面。
- 地图资源访问链路
Renderer -> local-map:// -> Electron Main -> 本地资源 / MBTiles / 后端接口
这是本项目比较有特色的一点。
通过自定义协议,地图瓦片和本地资源不必强依赖浏览器直接跨域访问,也不需要额外起一个本地静态资源服务,减少了部署复杂度。
这类设计非常适合离线 GIS 系统,因为本地瓦片、本地专题图、离线底图都能得到统一调度。
7 为什么说这套架构"简单"
很多项目复杂,并不是因为需求复杂,而是因为架构自己把自己绕复杂了。
这套架构之所以简单,不是因为它功能少,而是因为它从一开始就遵循了三个原则:
-
每一层只做自己的事
前端只管展示与交互
后端只管接口与业务
Electron 只管桌面能力和本地资源调度
-
路径统一
无论是 Web 版还是桌面版,很多请求路径都尽量保持一致,降低了环境切换成本。
-
尽量使用成熟方案
Vue 做前端
FastAPI 做后端
SQLite 做单机数据存储
Electron 做离线桌面封装
全都是成熟技术,没有刻意发明新轮子。
真正好的架构,往往长得都不新鲜。
因为它不是为了"惊艳",而是为了"稳定"。
8 为什么说它轻量级
轻量级不是看代码行数,而是看系统是否"依赖少、部署轻、维护省"。
这个项目的轻量化主要体现在以下几个方面:
-
数据库轻
使用 SQLite 作为主存储,不需要额外部署数据库服务。
-
部署轻
桌面版可以直接携带本地数据文件和资源文件,减少环境依赖。
-
资源调度轻
本地地图资源通过自定义协议直接读取,不额外引入复杂的本地静态资源服务层。
-
前端技术栈轻
地图能力基于 Leaflet 组合实现,没有引入特别庞大的前端 GIS 平台框架。
-
系统结构轻
虽然系统功能完整,但整体仍然是"单体后端 + Web 前端 + Electron 壳"的结构,足够清楚,也足够可控。
对很多项目来说,"轻量级"不是降级,而是更贴近交付现实。
9 为什么说它具备安全性
这里说的安全性,不是互联网超高对抗场景下的那种"零信任级别安全体系",而是更符合离线政务和行业系统的 实用型安全设计。
它的安全设计主要集中在四个方面。
- 后端统一鉴权
后端通过统一中间件拦截请求,除登录、健康检查、部分公开资源外,其余接口都要求携带认证信息。
这意味着系统不是"接口随便开",而是有统一入口、有统一校验。
- 桌面端能力隔离
Electron 通过 preload 暴露有限白名单 API,前端页面不能直接任意调用 Node 能力。
这是 Electron 应用里非常重要的一条安全边界。
简单说就是:
页面有页面的权限,系统有系统的权限,不能混着来。
- 本地协议访问控制
项目使用了 local-map:// 自定义协议读取本地资源,同时对路径进行了归一化和越界校验,避免通过路径拼接读取资源目录之外的文件。
这一点很关键,因为本地协议一旦处理粗糙,就很容易留下路径穿越风险。
- 授权校验机制
系统启动时会进行授权校验,授权异常会阻止服务正常运行。
对离线交付系统来说,这不是可选项,而是必要项。
它既保护软件交付边界,也保证运行环境受控。
- MBTiles 访问约束
MBTiles 资源访问并不是完全裸露的,资源标识经过安全格式校验,避免直接拼接路径造成非法文件访问。
10 这套架构最适合什么场景
如果总结这套架构的适用范围,我认为它非常适合以下类型项目:
离线 GIS 展示系统
单机版政务专题应用
农业调查与普查系统
需要本地数据、授权控制、地图展示的行业软件
对部署复杂度敏感、对交付稳定性要求高的项目
它不追求"无限扩展",而是追求:
有限边界内的高可用、高稳定、低维护。
这其实比一味追求架构时髦更有价值。
11 总结
这套离线土壤 GIS 系统的架构设计,本质上是在做一件事:
用尽可能简单的技术组合,完成一个真正可交付、可离线、可维护、可控的业务系统。
它的核心特点可以总结为三句话:
-
简单
边界清晰,职责明确,前后端与桌面端分工合理。
-
轻量级
SQLite、本地资源、自定义协议、克制的技术选型,让部署和维护成本都保持在较低水平。
-
安全可控
统一鉴权、能力隔离、路径校验、授权机制,共同构成了系统在离线场景下的安全闭环。
对于很多行业项目来说,真正优秀的架构并不是最复杂的架构,而是最适合业务现场、最容易稳定运行的架构。
这套方案也正是基于这样的原则落地的:
不追求炫技,只追求可靠。
12 后记
做离线系统和做互联网系统最大的不同是,前者更看重"能不能稳定落地",而不是"能不能无限放大"。
所以很多时候,工程上的高级感,并不来自组件数量,也不来自架构图有多少箭头,而是来自一句话:
现场能跑,出了问题能查,换台机器还能继续跑。
这才是离线系统真正的含金量。