通过在 Workers KV 中存储静态资源,你可以在全球以低延迟、高吞吐量检索这些资源。然后你可以直接提供这些资源,或使用它们动态生成响应。这在提供自定义脚本、符合 KV 限制 的小图像等文件,或从静态资源(如翻译)生成动态 HTML 响应时很有用。
要在 Workers KV 中存储静态资源,你可以使用 Wrangler CLI(通常在开发期间使用)、来自 Workers 应用的 Workers KV 绑定(binding),或 Workers KV REST API(通常用于从外部应用访问 Workers KV)。我们将演示如何使用 Wrangler CLI。
在此场景中,我们将在 Workers KV 存储中存储一个示例 HTML 文件。
创建包含以下内容的新文件 index.html:
Hello World!然后我们可以使用以下 Wrangler 命令在此文件的生产和预览命名空间中创建 KV 对:
npx wrangler kv key put index.html --path index.html --namespace-id=<ENTER_NAMESPACE_ID_HERE>这将在 Wrangler 文件中绑定指定的生产和预览命名空间内创建一个 KV 对,以文件名作为键,文件内容作为值。
在本示例中,我们的 Workers 应用将接受任何键名作为 HTTP 请求的路径,并返回 KV 存储中该键存储的值。
import mime from "mime";
interface Env {
assets: KVNamespace;
}
export default {
async fetch(request, env, ctx): Promise<Response> {
// Return error if not a get request
if(request.method !== 'GET'){
return new Response('Method Not Allowed', {
status: 405,
})
}
// Get the key from the url & return error if key missing
const parsedUrl = new URL(request.url)
const key = parsedUrl.pathname.replace(/^\/+/, '') // Strip any preceding /'s
if(!key){
return new Response('Missing path in URL', {
status: 400
})
}
// Get the mimetype from the key path
const extension = key.split('.').pop();
let mimeType = mime.getType(extension) || "text/plain";
if (mimeType.startsWith("text") || mimeType === "application/javascript") {
mimeType += "; charset=utf-8";
}
// Get the value from the Workers KV store and return it if found
const value = await env.assets.get(key, 'arrayBuffer')
if(!value){
return new Response("Not found", {
status: 404
})
}
// Return the response from the Workers application with the value from the KV store
return new Response(value, {
status: 200,
headers: new Headers({
"Content-Type": mimeType
})
});
},
} satisfies ExportedHandler<Env>;{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "<ENTER_WORKER_NAME>",
"main": "src/index.ts",
"compatibility_date": "2025-03-03",
"observability": {
"enabled": true
},
"kv_namespaces": [
{
"binding": "assets",
"id": "<YOUR_BINDING_ID>"
}
]
}此代码解析 HTTP 请求中要获取的键值对的键名。然后,它确定响应的正确 MIME 类型,以告知浏览器如何处理响应。
要从 KV 存储检索值,此代码使用 arrayBuffer 来正确处理二进制数据,如图像、文档以及视频/音频文件。
给定 Workers KV 命名空间存储中键为 index.html、值包含一些 HTML 内容的示例键值对,我们可以访问 Workers 应用
https://<YOUR-WORKER-HOSTNAME>/index.html 以查看 index.html 文件的内容。
尝试使用图像或文档,你会看到此 Worker 也能正确从 KV 提供这些资源。
除了提供静态资源,我们还可以根据 KV 存储中的值生成动态 HTML 或 API 响应。
- 首先在项目根目录创建此文件:
[
{
"language_code": "en",
"message": "Hello World!"
},
{
"language_code": "es",
"message": "¡Hola Mundo!"
},
{
"language_code": "fr",
"message": "Bonjour le monde!"
},
{
"language_code": "de",
"message": "Hallo Welt!"
},
{
"language_code": "zh",
"message": "你好,世界!"
},
{
"language_code": "ja",
"message": "こんにちは、世界!"
},
{
"language_code": "hi",
"message": "नमस्ते दुनिया!"
},
{
"language_code": "ar",
"message": "مرحبا بالعالم!"
}
]- 打开终端并输入以下 KV 命令,为翻译文件创建 KV 条目:
npx wrangler kv key put hello-world.json --path hello-world.json --namespace-id=<ENTER_NAMESPACE_ID_HERE>- 更新 Workers 代码,添加根据请求的 Accept-Language 标头语言提供翻译 HTML 文件的逻辑:
import mime from 'mime';
import parser from 'accept-language-parser'
interface Env {
assets: KVNamespace;
}
export default {
async fetch(request, env, ctx): Promise<Response> {
// Return error if not a get request
if(request.method !== 'GET'){
return new Response('Method Not Allowed', {
status: 405,
})
}
// Get the key from the url & return error if key missing
const parsedUrl = new URL(request.url)
const key = parsedUrl.pathname.replace(/^\/+/, '') // Strip any preceding /'s
if(!key){
return new Response('Missing path in URL', {
status: 400
})
}
// Add handler for translation path (with early return)
if(key === 'hello-world'){
// Retrieve the language header from the request and the translations from Workers KV
const languageHeader = request.headers.get('Accept-Language') || 'en' // Default to English
const translations : {
"language_code": string,
"message": string
}[] = await env.assets.get('hello-world.json', 'json') || [];
// Extract the requested language
const supportedLanguageCodes = translations.map(item => item.language_code)
const languageCode = parser.pick(supportedLanguageCodes, languageHeader, {
loose: true
})
// Get the message for the selected language
let selectedTranslation = translations.find(item => item.language_code === languageCode)
if(!selectedTranslation) selectedTranslation = translations.find(item => item.language_code === "en")
const helloWorldTranslated = selectedTranslation!['message'];
// Generate and return the translated html
const html = `<!DOCTYPE html>
<html>
<head>
<title>Hello World translation</title>
</head>
<body>
<h1>${helloWorldTranslated}</h1>
</body>
</html>
`
return new Response(html, {
status: 200,
headers: {
'Content-Type': 'text/html; charset=utf-8'
}
})
}
// Get the mimetype from the key path
const extension = key.split('.').pop();
let mimeType = mime.getType(extension) || "text/plain";
if (mimeType.startsWith("text") || mimeType === "application/javascript") {
mimeType += "; charset=utf-8";
}
// Get the value from the Workers KV store and return it if found
const value = await env.assets.get(key, 'arrayBuffer')
if(!value){
return new Response("Not found", {
status: 404
})
}
// Return the response from the Workers application with the value from the KV store
return new Response(value, {
status: 200,
headers: new Headers({
"Content-Type": mimeType
})
});
},
} satisfies ExportedHandler<Env>;{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "<ENTER_WORKER_NAME>",
"main": "src/index.ts",
"compatibility_date": "2025-03-03",
"observability": {
"enabled": true
},
"kv_namespaces": [
{
"binding": "assets",
"id": "<YOUR_BINDING_ID>"
}
]
}此新代码提供特定端点 /hello-world,将提供翻译响应。访问此 URL 时,Worker 代码将首先检索客户端在 Accept-Language 请求标头中请求的语言,以及 KV 存储中 hello-world.json 键的翻译。然后获取翻译消息并返回生成的 HTML。
访问 Worker 应用 https://<YOUR-WORKER-HOSTNAME>/hello-world 时,我们可以注意到应用现在返回正确翻译的 "Hello World" 消息。
从浏览器的开发者控制台更改区域语言(在 Chromium 浏览器中,运行 Show Sensors 以获取区域选择下拉菜单)。你会看到 Worker 现在根据区域语言返回翻译消息。