# MeshRay 路由注册顺序检查清单

**创建时间**: 2026-03-24  
**目的**: **防止再次犯同样的路由顺序错误！**

---

## ⚠️ **血的教训**

这个问题已经犯了**至少两次**：
1. ❌ 在 Go Embed 最佳实践文档中，示例代码写错了顺序
2. ❌ 在实际修复 MIME 类型问题时，又犯了同样的错误

**根本原因**: 没有形成肌肉记忆，没有使用检查清单

---

## ✅ **路由注册顺序（必须遵守）**

### 正确的顺序（从高优先级到低优先级）

```go
// 1️⃣ 中间件（最优先）
s.engine.Use(middleware.RequestLogger())
s.engine.Use(middleware.CORS())

// 2️⃣ 精确路由（具体路径）
s.engine.GET("/health", healthHandler)
s.engine.POST("/api/v1/login", loginHandler)

// 3️⃣ ⭐ 静态文件目录（高优先级，必须在 NoRoute 之前）
s.engine.StaticFS("/assets", httpFS)
s.engine.StaticFS("/static", httpFS)

// 4️⃣ 通配符路由（参数路由）
s.engine.GET("/files/:filepath", fileHandler)

// 5️⃣ ⭐ NoRoute 兜底路由（最低优先级，必须最后）
s.engine.NoRoute(func(c *gin.Context) {
    // SPA 路由支持
})
```

---

## 📋 **Checklist - 每次修改路由时都要检查**

### 开发阶段

- [ ] **确认路由注册顺序正确**
  - [ ] StaticFS 在 NoRoute 之前
  - [ ] 精确路由在 StaticFS 之前
  - [ ] 中间件在最前面

- [ ] **添加注释标记**
  ```go
  // ⭐ 重要：先注册静态文件目录（优先级高）
  s.engine.StaticFS("/assets", httpFS)
  
  // 再注册 NoRoute 处理 SPA 路由（优先级低）
  s.engine.NoRoute(...)
  ```

---

### Code Review 阶段

- [ ] **重点检查路由顺序**
  - [ ] StaticFS 是否在 NoRoute 之前？
  - [ ] 是否有其他路由可能拦截静态资源？
  - [ ] 注释是否清晰标明顺序要求？

- [ ] **功能测试**
  - [ ] JS 文件返回 `application/javascript`
  - [ ] CSS 文件返回 `text/css`
  - [ ] HTML 文件返回 `text/html`
  - [ ] 浏览器无 MIME 类型错误

---

### 测试验证

**快速测试命令**:
```bash
# 测试 JS 文件 MIME 类型
curl -I http://localhost:9531/assets/index.js | grep Content-Type
# 应该返回：application/javascript

# 测试 CSS 文件 MIME 类型
curl -I http://localhost:9531/assets/style.css | grep Content-Type
# 应该返回：text/css

# 测试 HTML 页面
curl http://localhost:9531 | grep "<!DOCTYPE html>"
# 应该返回：<!DOCTYPE html>
```

---

## 🔴 **错误示例（千万不要这样写）**

```go
// ❌ 错误示范 - 这个顺序会导致静态文件全部返回 HTML！
if staticFS != nil {
    httpFS := http.FS(staticFS)
    
    // ❌ 先注册 NoRoute（错误！）
    s.engine.NoRoute(func(c *gin.Context) {
        // 所有请求都被这里拦截
    })
    
    // ❌ 后注册 StaticFS（永远不会被执行）
    s.engine.StaticFS("/assets", httpFS)
}
```

**后果**:
- ❌ 所有 `/assets/*.js` 返回 HTML
- ❌ 所有 `/assets/*.css` 返回 HTML
- ❌ 浏览器控制台大量 MIME 类型错误
- ❌ 前端完全无法使用

---

## 🟢 **正确示例（必须这样写）**

```go
// ✅ 正确示范 - 严格按照优先级顺序
if staticFS != nil {
    httpFS := http.FS(staticFS)
    
    // ✅ 先注册静态文件目录（高优先级）
    s.engine.StaticFS("/assets", httpFS)
    s.engine.StaticFS("/static", httpFS)
    
    // ✅ 再注册 NoRoute（低优先级）
    s.engine.NoRoute(func(c *gin.Context) {
        // SPA 路由支持
    })
}
```

**效果**:
- ✅ JS 文件正确返回 `application/javascript`
- ✅ CSS 文件正确返回 `text/css`
- ✅ HTML 文件正确返回 `text/html`
- ✅ 前端正常工作

---

## 📊 **记忆口诀**

> **中间件最先注册，精确路由紧随其后；**  
> **静态文件要提前，NoRoute 最后面；**  
> **顺序千万别搞反，否则资源全完蛋！**

---

## 🎯 **如何形成肌肉记忆**

### 1. 每次写路由时都大声念出口诀
```
"静态文件要提前，NoRoute 最后面"
```

### 2. 在代码模板中固化顺序

创建代码片段（VSCode Snippet）:
```go
// Gin 路由模板
if staticFS != nil {
    httpFS := http.FS(staticFS)
    
    // ⭐ 重要：先注册静态文件目录（优先级高）
    ${1:s.engine.StaticFS("/assets", httpFS)}
    
    // 再注册 NoRoute 处理 SPA 路由（优先级低）
    ${2:s.engine.NoRoute(...)}
}
```

### 3. 在 IDE 中设置警告

如果使用 VSCode，可以创建自定义规则检测路由顺序。

---

## 📈 **历史错误记录**

| 时间 | 错误 | 影响 | 改进措施 |
|------|------|------|----------|
| 2026-03-24 (Go Embed 文档) | 示例代码顺序错误 | 文档误导他人 | 已修正并添加警告 |
| 2026-03-24 (MIME 修复) | 实际修复时顺序错误 | 前端无法访问 | 已修正并创建本清单 |

---

## ✅ **承诺**

从今天起，每次修改路由注册时都要：

1. 📝 **先看这个 Checklist**
2. 🔍 **检查顺序是否正确**
3. 🧪 **运行测试命令验证**
4. 📋 **Code Review 时重点检查**

**不再犯同样的错误！**

---

**状态**: ✅ **Checklist 已创建**  
**执行**: 每次修改路由时必须使用此清单  

*MeshRay - 从错误中学习，让教训成为财富！* ✨📋
