从108个Nginx Location到前端SPA:服务器路由的两大流派 / From 108 Nginx Locations to Frontend SPAs: Two Paradigms of Server Routing

今天在整理和排查服务器项目时,产生了一个很有意思的观察:关于 Web 服务的**路由管理(Routing)**,我们的服务器上正并存着两种截然相反的哲学。

一种是**“放手”的前端单页应用(SPA)**,Nginx 极其简单,只做个兜底,路由全交由浏览器里的 JavaScript 处理;另一种则是**“大包大揽”的 Nginx 微路由网关**,Nginx 管得极其细致,甚至单个配置文件里塞了上百个 location 块。

这篇日记详细总结一下今天的发现与思考。

### 流派一:极致的 JS 前端路由(SPA)

在这种结构中,Nginx 扮演的只是一个“静态文件搬运工”加“终极兜底人”的角色。

以我们服务器上的两个项目为例:
1. **Zashboard (mihomo.6767.chat)**:
它的 Nginx 配置异常干净,核心只有这一段:
“`nginx
location / {
root /home/ubuntu/workspace/ops/zashboard/current;
try_files $uri $uri/ /index.html;
}
“`
当浏览器访问 `/settings` 或者 `/connections` 时,Nginx 在物理目录下找不到对应的文件或目录,就会根据 `try_files` 的指示,乖乖把 `index.html` 返回给浏览器。接着,前端 JavaScript 脚本接管一切,通过 HTML5 History API 识别当前路径,并显示对应的控制台模块。
2. **Kanna (ops/kanna – 挂载于 /codex/)**:
这是一个基于 React 的协作工作区。前端代码中引入了 `react-router-dom`。所有的子路由(如 `/codex/chat`、`/codex/settings`)在浏览器端完全由 JS 路由引擎渲染。而 Nginx 只需要做最基础的反向代理,把所有流量丢给底层的 Node/Bun 进程即可。

**优点**:前端体验极佳,页面切换无需刷新,极度顺滑。Nginx 配置清爽。
**缺点**:首屏加载较重,SEO 不够友好,且所有的路由跳转逻辑都暴露在前端代码中。

***

### 流派二:极致的 Nginx 微路由网关(Micro-routing)

与 SPA 的“放权”相反,主域名 `6767.chat` 走的是另一条路。它的配置文件 `/etc/nginx/platform/sites/6767.chat.conf` 里,**足足塞了 108 个 location 块**。

在这里,Nginx 变成了最核心的微服务网关,以一种近乎“手工缝合”的方式,管理着庞大而复杂的业务:

1. **微服务与端口精准分发 (Micro-routing to Ports)**:
不同的子路径被 Nginx 剥离,精准转发给本地运行在不同端口上的小微服务:
– `/api/zhihu-immersive-reader/` -> 转发至知乎沉浸阅读器服务(端口 `3013`)
– `/api/speech-assess/` -> 转发至语音测评服务(端口 `3011`)
– `/api/tts-proxy/` -> 转发至 TTS 代理服务(端口 `3012`)
– `/api/visits/` -> 转发至访问统计服务(端口 `3017`)
每一个独立功能都是一个微小的进程,Nginx 是它们的统一大门。
2. **静态目录交叉缝合 (Alias Mapping)**:
Nginx 使用 `alias` 直接接管了不同子路径的物理静态文件:
– `/qbank/` 映射到 `/static/6767-home/qbank/`
– `/archive/assets/` 映射到 `/static/6767-home/archive/assets/`
3. **统一拦截鉴权 (auth_request)**:
安全防护也由 Nginx 统一把关。比如敏感路径(如日志、监控),Nginx 会通过 `auth_request /_auth_verify` 拦截,内部重定向到鉴权接口(端口 `3021`)去校验 Cookie。通过了才放行,不通过直接在 Nginx 层返回 302 登录重定向。

**优点**:灵活性极高,能够把几十个完全不同语言(Node/Python/Go)、不同框架的静态网页和动态 API,天衣无缝地拼装在同一个域名和路径结构下,完美避开跨域问题,且集中控制了鉴权与安全。
**缺点**:Nginx 配置文件变得极度臃肿,任何细微的路径改动都需要 reload 甚至修改 Nginx,维护成本较高。

### 总结

这两种流派并没有优劣之分,而是为了解决不同的问题:
– 如果是一个高内聚、高交互的独立业务,**SPA + 前端 JS 路由**是最好的选择,干净利落。
– 如果是一个长年累月迭代、包含了无数小工具、独立脚本和微型服务的“混沌系统”,**Nginx 微路由网关**则是最强大的缝合剂,它能让不同技术栈的服务在同一个域名下相安无事。

今天对路由的重新梳理,让我对服务器的架构边界有了更清晰的认识。

***

Today, while organizing and troubleshooting the server projects, I came across a fascinating observation: when it comes to web service **routing management**, our server concurrently hosts two diametrically opposed philosophies.

One is the **”hands-off” Frontend Single Page Application (SPA)** paradigm, where Nginx remains incredibly simple and acts only as a fallback, leaving all routing logic to JavaScript in the browser. The other is the **”all-inclusive” Nginx Micro-Routing Gateway** approach, where Nginx micro-manages every path, packing over a hundred location blocks into a single configuration file.

Here is a detailed summary of today’s discoveries and thoughts.

### Paradigm 1: Extreme JS Frontend Routing (SPA)

In this setup, Nginx plays the role of a mere “static file courier” and an “ultimate safety net.”

Take two projects on our server as examples:
1. **Zashboard (mihomo.6767.chat)**:
Its Nginx config is exceptionally clean, with the core being just this block:
“`nginx
location / {
root /home/ubuntu/workspace/ops/zashboard/current;
try_files $uri $uri/ /index.html;
}
“`
When a user navigates to `/settings` or `/connections`, Nginx cannot find matching files in the physical directory. Instructed by `try_files`, it quietly serves `index.html`. Browser-side JavaScript then takes over, reads the current path via the HTML5 History API, and renders the correct dashboard component.
2. **Kanna (ops/kanna – mounted at /codex/)**:
A React-based collaborative workspace using `react-router-dom`. All sub-routes (e.g., `/codex/chat`, `/codex/settings`) are rendered entirely by the browser’s JS routing engine. Nginx only needs to perform basic reverse proxying, tossing the traffic to the underlying Node/Bun process.

**Pros**: Exceptional user experience with instantaneous, refresh-free page transitions. Highly elegant Nginx configs.
**Cons**: Heavy initial bundle size, poor SEO friendliness, and all routing logic is exposed to client-side code.

***

### Paradigm 2: Extreme Nginx Micro-Routing Gateway

In stark contrast to SPA’s decentralization, the primary domain `6767.chat` takes a completely different path. Its configuration file `/etc/nginx/platform/sites/6767.chat.conf` contains **exactly 108 location blocks**.

Here, Nginx acts as the core API Gateway, stitching a massive, sprawling list of services together by hand:

1. **Micro-routing to Ports**:
Nginx dissects different sub-paths and directs them to small microservices running on various local ports:
– `/api/zhihu-immersive-reader/` -> proxied to the 知乎 reader service (Port `3013`)
– `/api/speech-assess/` -> proxied to the pronunciation assessment service (Port `3011`)
– `/api/tts-proxy/` -> proxied to the TTS proxy service (Port `3012`)
– `/api/visits/` -> proxied to the visitor analytics service (Port `3017`)
Each feature functions as an isolated process; Nginx serves as the unified entry point.
2. **Stitching Static Directories (Alias Mapping)**:
Nginx uses `alias` to directly handle physical static directories for distinct sub-paths:
– `/qbank/` maps to `/static/6767-home/qbank/`
– `/archive/assets/` maps to `/static/6767-home/archive/assets/`
3. **Unified Authentication (auth_request)**:
Security is also consolidated at the Nginx layer. For sensitive routes, Nginx intercepts requests using `auth_request /_auth_verify`, redirecting internally to the auth service (Port `3021`) to validate cookies. It only permits traffic if authorized, returning a 302 login redirect otherwise.

**Pros**: Tremendous architectural flexibility. It stitches dozens of static web pages and dynamic APIs written in different languages (Node/Python/Go) and frameworks seamlessly under a single domain, bypassing CORS hurdles and centralizing security control.
**Cons**: The Nginx configuration becomes highly complex and bloated. Any minor path alteration requires modifying Nginx and reloading, increasing maintenance overhead.

### Conclusion

Neither paradigm is superior; rather, they solve distinct problems:
– For a highly cohesive, highly interactive standalone application, **SPA + frontend JS routing** is the cleanest choice.
– For a “chaotic system” evolved over years, incorporating dozens of tiny tools, standalone scripts, and micro-apps, the **Nginx Micro-Routing Gateway** is the ultimate adhesive. It allows services of entirely different tech stacks to coexist harmoniously under one domain.

Re-evaluating routing today has given me a much clearer perspective on our server’s architectural boundaries.

No Comments

Send Comment Edit Comment


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
Previous