Skip to content

静态文件服务

简介

HttpServer 内置静态文件服务功能,当配置 WebRoot 后,会自动处理静态资源请求,无需编写控制器。

版本变更说明

vbman 1.0.0.419 起,WebRootStart() 方法中独立为链式函数。旧版写法 Server.Start 8080, "C:\WebRoot" 不再支持,请改为 Server.WebRoot("C:\WebRoot").Start 8080

快速配置

vb
Private Sub Form_Load()
    Set Server = New cHttpServer

    ' 配置静态文件根目录
    Server.WebRoot("C:\WebRoot").Start 8080

    Debug.Print "静态文件服务: http://localhost:8080/"
End Sub

目录结构示例

C:\WebRoot\
├── index.html          # 首页
├── favicon.ico         # 网站图标
├── css\
│   ├── style.css
│   └── theme.css
├── js\
│   ├── app.js
│   └── utils.js
├── images\
│   ├── logo.png
│   └── banner.jpg
└── upload\
    └── avatar.png

请求映射

请求 URL映射到文件
/C:\WebRoot\index.html
/css/style.cssC:\WebRoot\css\style.css
/js/app.jsC:\WebRoot\js\app.js
/images/logo.pngC:\WebRoot\images\logo.png

支持的 MIME 类型

vb
' 系统自动识别以下文件类型的 Content-Type

' 文本类型
text/html          -> .html, .htm
text/css           -> .css
text/javascript    -> .js
text/plain         -> .txt

' 图片类型
image/png          -> .png
image/jpeg         -> .jpg, .jpeg
gif/image          -> .gif
image/svg+xml      -> .svg
image/x-icon       -> .ico

' 应用类型
application/json   -> .json
application/xml    -> .xml
application/pdf    -> .pdf

' 字体类型
font/woff2         -> .woff2
font/woff          -> .woff

默认文档机制

当请求路径对应一个目录时(如访问根路径 /),HttpServer 会自动查找默认文档,按优先级逐一尝试:

优先级默认文档
1index.html
2index.htm
3default.html
4default.htm

处理流程

请求 "/" 或 "/subdir/"


检查 WebRoot + 路径 是否为目录

   ├─> 是目录 → 遍历默认文档列表
   │     ├─> index.html 存在? → 返回文件 ✅
   │     ├─> index.htm 存在? → 返回文件 ✅
   │     ├─> default.html 存在? → 返回文件 ✅
   │     ├─> default.htm 存在? → 返回文件 ✅
   │     └─> 都不存在 → 返回 403 "Directory listing not allowed" 🔒

   └─> 不是目录 → 返回 404

添加自定义默认文档

vb
Private Sub Form_Load()
    Set Server = New cHttpServer

    ' 添加自定义默认文档(如 home.html)
    Server.AddDefaultDocument "home.html"
    ' 重复添加会自动忽略,不会重复入列

    Server.WebRoot("C:\WebRoot").Start 8080
End Sub

添加后,默认文档查找顺序变为:index.html → index.htm → default.html → default.htm → home.html

目录重定向

当请求路径对应物理目录但不以 / 结尾时,HttpServer 会自动 302 重定向到带 / 的路径:

请求 /subdir (对应物理目录)
   → 302 重定向到 /subdir/
   → 再按默认文档机制查找 /subdir/index.html 等

注意:根路径 / 不需要重定向,直接进入默认文档查找。

与路由的优先级关系

如果为根路径 / 注册了手动路由,路由优先执行,不会进入默认文档查找:

vb
' 路由优先:根路径由控制器处理
Call Server.Router.Add("/", "Home@Index")

' 此时访问 "/" → 调用 Home.Index,不查找 index.html

优先级说明

静态文件优先于路由匹配:

请求 /index.html

   ├──> 检查 C:\WebRoot\index.html 是否存在
   │     ├─> 存在 -> 返回静态文件
   │     └─> 不存在 -> 进入路由匹配

   └──> 匹配路由 /index.html

混合模式(静态文件 + API)

vb
Private Sub Form_Load()
    Set Server = New cHttpServer

    ' ========== 配置路由 ==========
    ' API 控制器
    Call Server.Router.Reg("Api", New cApiController)
    Call Server.Router.Add("/api/users", "Api@Users", OnlyGet)
    Call Server.Router.Add("/api/data", "Api@Data", OnlyGet)

    ' 业务控制器
    Call Server.Router.Reg("User", New cUserController)
    Call Server.Router.Add("/user/login", "User@Login", OnlyPost)

    ' ========== 启动服务 ==========
    ' WebRoot 用于静态文件,API 请求会进入路由
    Server.WebRoot("C:\WebRoot").Start 8080

    Debug.Print "服务启动成功"
    Debug.Print "  前端: http://localhost:8080/"
    Debug.Print "  API:  http://localhost:8080/api/users"
End Sub

单页应用 (SPA) 支持

对于 React/Vue/Angular 等 SPA,需要配置所有路由都返回 index.html:

vb
' cSpaController.cls
Public Sub Index(ctx As cHttpServerContext)
    ' 返回 index.html 让前端路由处理
    ctx.Response.File "/index.html"
End Sub

' 注册路由
Private Sub Form_Load()
    Set Server = New cHttpServer

    ' API 路由
    Call Server.Router.Reg("Api", New cApiController)
    Call Server.Router.Add("/api/*", "Api@Handle")

    ' SPA 路由:所有非 API 请求返回 index.html
    Call Server.Router.Reg("Spa", New cSpaController)
    Call Server.Router.Add("/*", "Spa@Index")

    Server.WebRoot("C:\WebRoot").Start 8080
End Sub

文件上传目录

vb
' 上传文件保存到静态目录
Public Sub Upload(ctx As cHttpServerContext)
    ' 保存上传的文件
    Dim savePath As String
    savePath = ctx.Server.WebRoot & "\upload\" & filename

    Call SaveUploadFile(ctx.Request.RawBodyBin, savePath)

    ' 返回可访问的 URL
    Dim result As New Dictionary
    result("url") = "/upload/" & filename
    ctx.Response.Json result
End Sub

缓存控制

内置懒缓存 + ETag + 304

HttpServer 内置了三层缓存机制,自动感知文件更新,无需手动干预:

请求 /css/style.css


1. 计算 ETag(文件修改时间 + 大小,仅FSO元数据,不读内容)

   ├─> 浏览器发送 If-None-Match 且匹配 → 304 Not Modified ✅
   │     (零传输,浏览器使用本地缓存)

   ├─> 缓存命中且 ETag 未变 → 内存输出(跳过磁盘 I/O) ✅

   ├─> 缓存命中但 ETag 变化 → 重新读取 + 更新缓存 🔄

   └─> 无缓存 → 磁盘读取 + 懒缓存(大小≤上限才加入) 📥

懒缓存规则

  • 默认不缓存任何文件
  • 首次访问时,如果文件大小 ≤ MaxCacheFileSize,自动加入内存缓存
  • 超出大小上限的文件(如视频、大图片)始终从磁盘读取,但仍享受 ETag/304 协商缓存
  • 文件在磁盘上更新后,ETag 自动变化,旧缓存自动失效并重新读取

缓存配置

vb
Private Sub Form_Load()
    Set Server = New cHttpServer

    ' 缓存配置(可在 Start 前或运行中随时修改)
    Server.MaxCacheFileSize = 1048576  ' 单文件缓存上限:1MB(默认)
    Server.CacheTTLSeconds = 300       ' 缓存TTL:5分钟(默认)

    ' 设置为0可禁用内容缓存(仅保留ETag/304协商缓存)
    Server.MaxCacheFileSize = 0

    Server.WebRoot("C:\WebRoot").Start 8080
End Sub
配置项默认值说明
MaxCacheFileSize1048576 (1MB)单文件缓存上限字节,0=禁用内容缓存
CacheTTLSeconds300 (5分钟)缓存TTL秒数,过期后检查ETag再决定是否刷新,0=永不过期

手动刷新缓存

部署新文件后,可手动刷新目录结构缓存和内容缓存:

vb
' 刷新目录结构缓存(新增/删除文件后调用)
' 不影响内容缓存,内容缓存通过ETag自动感知文件更新
Server.RefreshCache

' 清空所有文件内容缓存(强制重新从磁盘读取)
Server.ClearFileCache

最佳实践:大多数场景只需 RefreshCache,内容缓存会通过 ETag 自动感知文件更新。只有当需要强制释放内存时才用 ClearFileCache

自定义中间件缓存头

vb
' cCacheMiddleware.cls
Public Sub Entry(ctx As cHttpServerContext)
    ' 静态文件添加浏览器缓存头
    If IsStaticFile(ctx.Request.PathInfo) Then
        ' 缓存 1 小时
        ctx.Response.Header("Cache-Control") = "public, max-age=3600"
    End If
End Sub

Private Function IsStaticFile(path As String) As Boolean
    Dim ext As String
    ext = LCase(Mid(path, InStrRev(path, ".")))

    IsStaticFile = (ext = ".css" Or ext = ".js" Or ext = ".png" Or _
                    ext = ".jpg" Or ext = ".gif" Or ext = ".ico")
End Function

最后更新: 2026-06-22

VB6及其LOGO版权为微软公司所有