129 lines
4.3 KiB
JavaScript
129 lines
4.3 KiB
JavaScript
/**
|
|
* Cloudflare Workers 静态站点服务 (Wrangler 4.x 兼容)
|
|
*
|
|
* @param {Request} request
|
|
* @param {Object} env - 环境变量,包含 ASSETS 绑定
|
|
* @param {ExecutionContext} ctx
|
|
* @returns {Promise<Response>}
|
|
*/
|
|
export default {
|
|
async fetch(request, env, ctx) {
|
|
const url = new URL(request.url);
|
|
const pathname = url.pathname;
|
|
|
|
// 🏠 根路径处理
|
|
if (pathname === '/' || pathname === '/index') {
|
|
url.pathname = '/index.html';
|
|
}
|
|
|
|
try {
|
|
// 🔍 检查 ASSETS 是否存在
|
|
if (!env.ASSETS) {
|
|
throw new Error('ASSETS binding not configured. Check wrangler.toml configuration.');
|
|
}
|
|
|
|
// 🔍 获取静态资源
|
|
let response = await env.ASSETS.fetch(url);
|
|
|
|
// 🚫 404 处理
|
|
if (response.status === 404) {
|
|
try {
|
|
const notFoundResponse = await env.ASSETS.fetch('/404.html');
|
|
if (notFoundResponse.ok) {
|
|
response = new Response(notFoundResponse.body, {
|
|
...notFoundResponse,
|
|
status: 404,
|
|
statusText: 'Not Found'
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.warn('Custom 404 page not available, using default');
|
|
response = new Response(`
|
|
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>404 - 页面未找到</title>
|
|
<style>
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
|
|
text-align: center;
|
|
padding: 50px;
|
|
background: #f5f5f5;
|
|
color: #333;
|
|
}
|
|
h1 {
|
|
color: #ff4444;
|
|
font-size: 3em;
|
|
margin: 20px 0;
|
|
}
|
|
p {
|
|
color: #666;
|
|
font-size: 1.2em;
|
|
margin: 20px 0;
|
|
}
|
|
a {
|
|
color: #0066cc;
|
|
text-decoration: none;
|
|
}
|
|
a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>404</h1>
|
|
<p>抱歉,您访问的页面不存在</p>
|
|
<p><a href="/">返回首页</a></p>
|
|
</body>
|
|
</html>
|
|
`.trim(), {
|
|
status: 404,
|
|
headers: {
|
|
'Content-Type': 'text/html; charset=utf-8'
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// ⚙️ 优化响应
|
|
return this.optimizeResponse(response, pathname);
|
|
|
|
} catch (error) {
|
|
console.error('Worker error:', error);
|
|
return new Response(`服务暂时不可用: ${error.message}`, {
|
|
status: 503,
|
|
headers: {
|
|
'Content-Type': 'text/plain; charset=utf-8'
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
optimizeResponse(response, pathname) {
|
|
const newResponse = new Response(response.body, response);
|
|
const headers = newResponse.headers;
|
|
const contentType = headers.get('Content-Type') || '';
|
|
|
|
// 🔒 安全头
|
|
headers.set('X-Content-Type-Options', 'nosniff');
|
|
headers.set('X-Frame-Options', 'DENY');
|
|
headers.set('X-XSS-Protection', '1; mode=block');
|
|
headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
|
|
|
|
// 📦 智能缓存
|
|
if (/\.(js|css|png|jpg|jpeg|gif|svg|webp|woff2|woff|ttf|eot|ico|json)$/.test(pathname)) {
|
|
headers.set('Cache-Control', 'public, max-age=31536000, immutable');
|
|
} else if (pathname.endsWith('.html')) {
|
|
headers.set('Cache-Control', 'public, max-age=3600, stale-while-revalidate=86400');
|
|
} else {
|
|
headers.set('Cache-Control', 'public, max-age=86400');
|
|
}
|
|
|
|
// 🌐 CORS
|
|
headers.set('Access-Control-Allow-Origin', '*');
|
|
|
|
return newResponse;
|
|
}
|
|
}; |