如果您使用 unjs/listhen
,您只需在项目根目录中创建一个 public
目录并将静态资产放入其中。它们将自动提供。
用法
要提供静态目录,您可以使用 serveStatic
实用程序。
import { createApp, defineEventHandler, serveStatic } from 'h3'
export const app = createApp()
app.use(
defineEventHandler((event) => {
return serveStatic(event, {
getContents: (id) => {
return undefined
},
getMeta: (id) => {
return undefined
},
})
}),
)
这还不能提供任何文件。您需要实现 getContents
和 getMeta
方法。
getContents
用于读取文件的内容。它应该返回一个解析为文件内容的Promise
,如果文件不存在则返回undefined
。getMeta
用于获取文件的元数据。它应该返回一个解析为文件元数据的Promise
,如果文件不存在则返回undefined
。
它们是分开的,以允许 h3 响应 HEAD
请求而不读取文件的内容并使用 Last-Modified
标头。
读取文件
现在,在 public
目录中创建一个带有简单消息的 index.html
文件,然后打开浏览器访问 http://localhost:3000。您应该会看到该消息。
public
的使用是一种惯例,但您可以使用任何您想要的目录名称。
如果您正在使用 unjs/listhen
并想尝试此示例,请创建一个名称不同于 public
的目录,因为它是 listhen
使用的默认目录。
然后,我们可以创建 getContents
和 getMeta
方法:
import { readFile, stat } from 'node:fs/promises'
import { createApp, defineEventHandler, serveStatic } from 'h3'
import { join } from 'pathe'
export const app = createApp()
const publicDir = 'assets'
app.use(
defineEventHandler((event) => {
return serveStatic(event, {
getContents: id => readFile(join(publicDir, id)),
getMeta: async (id) => {
const stats = await stat(join(publicDir, id)).catch(() => {})
if (!stats || !stats.isFile()) {
return
}
return {
size: stats.size,
mtime: stats.mtimeMs,
}
},
})
}),
)
getContents
读取文件并返回其内容,非常简单。getMeta
使用 fs.stat
获取文件元数据。如果文件不存在或不是文件,则返回 undefined
。否则,返回文件大小和上次修改时间。
如果文件自上次请求以来没有被修改,则使用文件大小和上次修改时间创建 etag 以发送 304 Not Modified
响应。如果文件没有更改,这可以避免多次发送相同的文件。
解析资产
如果路径与文件不匹配,h3 将尝试将 index.html
添加到路径并重试。如果仍然不匹配,它将返回 404 错误。
您可以通过将 indexNames
选项传递给 serveStatic
来更改此行为:
import { createApp, serveStatic } from 'h3'
const app = createApp()
app.use(
serveStatic({
indexNames: ['/app.html', '/index.html'],
}),
)
使用此选项,h3 将首先尝试匹配 <path>/app.html
,然后是 <path>/index.html
,最后返回 404 错误。
不要忘记 h3 开头的 /
将路径与索引名称连接起来。例如,/index.html
将与 /hello
连接起来形成 hello/index.html
。