/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}
前端静态资源与 API 同域部署:Ingress Nginx 路由与 BFF 架构

在现代全栈微服务架构中,很多团队习惯将前端单页应用(SPA)部署在独立的静态资源 CDN 域名(如 static.example.com),而后端接口部署在 api.example.com。
这种跨域分离部署在初期虽然部署简单,但在进入中大型业务阶段后,会暴露出三大难以调和的架构痛点:
通过 Kubernetes Ingress-Nginx 的路径由(Path-based Routing) 将前端静态托管与 BFF(Backend for Frontend)网关收敛到同一域名下,是消除跨域损耗、统一安全边界的标准云原生解法。
统一网关与同域分流架构
[统一入口: https://app.internal.net]
│
▼
[Kubernetes Ingress-Nginx 控制器]
│
┌─────────────────────────┴─────────────────────────┐
▼ ▼
[路径 / (默认全部静态资源)] [路径 /api/v1/ (BFF 聚合接口)]
│ │
▼ ▼
[Frontend Nginx Pod] [Node.js / Go BFF Pod]
– 协商缓存 (index.html no-cache) – 会话鉴权与 HttpOnly Cookie 校验
– 强缓存 (JS/CSS/WebP 1年) – 聚合下游微服务 gRPC/HTTP
– History API 路由回退 – SSE 流式长连接无缓冲转发
生产级 Ingress 路由配置实现
在同一个 Ingress 规则中,通过严格的路径前缀匹配(Prefix Matching)实现流量的精准切分,并针对 API 链路与静态资源链路分别施加差异化的代理策略:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: frontend-bff-unified-ingress
namespace: production
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/cluster-issuer: "letsencrypt-production"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
# 全局超时设置:针对长耗时 API 留足 120 秒超时缓冲
nginx.ingress.kubernetes.io/proxy-connect-timeout: "10"
nginx.ingress.kubernetes.io/proxy-read-timeout: "120"
nginx.ingress.kubernetes.io/proxy-send-timeout: "120"
# 针对流式 SSE 接口彻底关闭 Nginx 代理缓冲区
nginx.ingress.kubernetes.io/proxy-buffering: "off"
# 启用 gzip 压缩加速文本传输
nginx.ingress.kubernetes.io/use-gzip: "true"
nginx.ingress.kubernetes.io/gzip-types: "text/plain text/css application/javascript application/json image/svg+xml"
spec:
tls:
– hosts:
– app.internal.net
secretName: app-internal-tls-secret
rules:
– host: app.internal.net
http:
paths:
# 1. 优先匹配 API 网关路径
– path: /api
pathType: Prefix
backend:
service:
name: bff-gateway-service
port:
number: 3000
# 2. 兜底匹配前端静态资源
– path: /
pathType: Prefix
backend:
service:
name: frontend-static-service
port:
number: 80
前端 Nginx 容器的高性能缓存与 SPA 路由兜底
在 frontend-static-service 的 Docker 镜像中,编写专门针对现代打包工具(Vite/Webpack)产物特性的 nginx.conf:
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# 1. 带 Content-Hash 的不可变静态资产:开启 1 年强缓存
location ~* \\.(js|css|webp|png|jpg|woff2|ttf)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
access_log off;
}
# 2. HTML 入口文件:永不缓存,确保版本更新实时触达用户
location = /index.html {
expires -1;
add_header Cache-Control "no-store, no-cache, must-revalidate";
add_header Pragma "no-cache";
}
# 3. 前端 SPA History 路由支持:任何未命中文件的路径重定向到 index.html
location / {
try_files $uri $uri/ /index.html;
}
}


