跳转到内容
搜索文档

存储和检索静态资源

在 Workers KV 中存储静态资源,并以低延迟、高吞吐量从 Worker 应用提供这些资源

最后更新 查看 MarkdownAgent 设置

通过在 Workers KV 中存储静态资源,你可以在全球以低延迟、高吞吐量检索这些资源。然后你可以直接提供这些资源,或使用它们动态生成响应。这在提供自定义脚本、符合 KV 限制 的小图像等文件,或从静态资源(如翻译)生成动态 HTML 响应时很有用。

使用 Wrangler 将静态资源写入 Workers KV

要在 Workers KV 中存储静态资源,你可以使用 Wrangler CLI(通常在开发期间使用)、来自 Workers 应用的 Workers KV 绑定(binding),或 Workers KV REST API(通常用于从外部应用访问 Workers KV)。我们将演示如何使用 Wrangler CLI。

在此场景中,我们将在 Workers KV 存储中存储一个示例 HTML 文件。

创建包含以下内容的新文件 index.html

index.htmlhtml
Hello World!

然后我们可以使用以下 Wrangler 命令在此文件的生产和预览命名空间中创建 KV 对:

npx wrangler kv key put index.html --path index.html --namespace-id=<ENTER_NAMESPACE_ID_HERE>

这将在 Wrangler 文件中绑定指定的生产和预览命名空间内创建一个 KV 对,以文件名作为键,文件内容作为值。

从 Worker 应用提供 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 响应。

  1. 首先在项目根目录创建此文件:
hello-world.jsonjson
[
	{
		"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": "مرحبا بالعالم!"
	}
]
  1. 打开终端并输入以下 KV 命令,为翻译文件创建 KV 条目:
npx wrangler kv key put hello-world.json --path hello-world.json --namespace-id=<ENTER_NAMESPACE_ID_HERE>
  1. 更新 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 现在根据区域语言返回翻译消息。

相关资源

这篇文档对您有帮助吗?