feat: add dynamic robots.txt and sitemap.xml route handlers
This commit is contained in:
87
layers/server/routes/robots.txt.ts
Normal file
87
layers/server/routes/robots.txt.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
// server/routes/robots.txt.ts
|
||||
type RobotsConfig = {
|
||||
userAgent?: string | string[]
|
||||
allow?: string[]
|
||||
disallow?: string[]
|
||||
sitemap?: string | string[]
|
||||
host?: string
|
||||
cache?: { sMaxAge?: number; staleWhileRevalidate?: number }
|
||||
}
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const host =
|
||||
(getHeader(event, "host") || getRequestHost(event)).toString() || "";
|
||||
const baseDomain = process.env.BASE_DOMAIN || ".onstove.com";
|
||||
const isGameAliasExtractable = host.includes(baseDomain);
|
||||
|
||||
if (isGameAliasExtractable) {
|
||||
const gameAlias = host.split(".")[0];
|
||||
console.log("🚀 ~ 333 gameAlias:", gameAlias)
|
||||
}
|
||||
|
||||
// if (gameAlias && gameAlias !== "www") {
|
||||
// event.context.gameAlias = gameAlias;
|
||||
// }
|
||||
// }
|
||||
// robots 설정을 직접 가져오기 (미들웨어 context 사용)
|
||||
|
||||
let config: RobotsConfig;
|
||||
|
||||
try {
|
||||
// 외부 API에서 robots 설정 가져오기
|
||||
const response = await $fetch('https://static-pubcomm.gate8.com/dev/test0905/dataization/test0905_homepage_brand_siteConfig.json');
|
||||
|
||||
// robots 설정 추출
|
||||
const robotsConfig = response.robots?.rules?.[0] || {
|
||||
userAgent: "*",
|
||||
allow: ["/"],
|
||||
disallow: ["/error2", "/inspection/", "/inspection/*", "/html/*"]
|
||||
};
|
||||
|
||||
config = {
|
||||
userAgent: robotsConfig.userAgent,
|
||||
allow: robotsConfig.allow,
|
||||
disallow: robotsConfig.disallow,
|
||||
sitemap: robotsConfig.sitemap,
|
||||
cache: { sMaxAge: 300, staleWhileRevalidate: 600 }
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch robots config:', error);
|
||||
|
||||
// 에러 발생 시 기본값 반환
|
||||
config = {
|
||||
userAgent: "*",
|
||||
allow: ["/"],
|
||||
disallow: ["/error", "/inspection/", "/inspection/*", "/html/*"],
|
||||
sitemap: ["https://l922.onstove.com/sitemap.xml"],
|
||||
host: "epic7.onstove.com",
|
||||
cache: { sMaxAge: 300, staleWhileRevalidate: 600 }
|
||||
};
|
||||
}
|
||||
|
||||
setHeader(event, "Content-Type", "text/plain; charset=utf-8")
|
||||
|
||||
// 캐시 헤더 (CDN 친화)
|
||||
const sMax = config.cache?.sMaxAge ?? 300
|
||||
const swr = config.cache?.staleWhileRevalidate ?? 600
|
||||
setHeader(event, "Cache-Control", `public, s-maxage=${sMax}, stale-while-revalidate=${swr}`)
|
||||
|
||||
// 여러 user-agent 지원
|
||||
const agents = Array.isArray(config.userAgent) ? config.userAgent : [config.userAgent ?? "*"]
|
||||
|
||||
const lines: string[] = []
|
||||
for (const ua of agents) {
|
||||
lines.push(`User-agent: ${ua}`)
|
||||
for (const p of config.allow ?? []) lines.push(`Allow: ${p}`)
|
||||
for (const p of config.disallow ?? []) lines.push(`Disallow: ${p}`)
|
||||
lines.push("") // 블록 구분 공백
|
||||
}
|
||||
|
||||
const sitemaps = Array.isArray(config.sitemap) ? config.sitemap : (config.sitemap ? [config.sitemap] : [])
|
||||
for (const sm of sitemaps) lines.push(`Sitemap: ${sm}`)
|
||||
if (config.host) lines.push(`Host: ${config.host}`)
|
||||
|
||||
// 마지막 개행
|
||||
return lines.join("\n").trim() + "\n"
|
||||
})
|
||||
|
||||
67
layers/server/routes/sitemap.xml.ts
Normal file
67
layers/server/routes/sitemap.xml.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
// server/routes/sitemap.xml.ts
|
||||
type SitemapUrl = {
|
||||
loc: string
|
||||
lastmod?: string
|
||||
changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never'
|
||||
priority?: number
|
||||
}
|
||||
|
||||
type SitemapConfig = {
|
||||
urls: SitemapUrl[]
|
||||
cache?: { sMaxAge?: number; staleWhileRevalidate?: number }
|
||||
}
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const host = (getHeader(event, "host") || getRequestHost(event)).toString() || "";
|
||||
const baseDomain = process.env.BASE_DOMAIN || ".onstove.com";
|
||||
const isGameAliasExtractable = host.includes(baseDomain);
|
||||
|
||||
let gameAlias = "";
|
||||
if (isGameAliasExtractable) {
|
||||
gameAlias = host.split(".")[0] || "";
|
||||
}
|
||||
|
||||
let config: SitemapConfig;
|
||||
|
||||
|
||||
try {
|
||||
// 외부 API에서 sitemap 설정 가져오기
|
||||
const response = await $fetch('https://static-pubcomm.gate8.com/dev/test0905/dataization/test0905_homepage_brand_siteConfig.json') as any;
|
||||
|
||||
// sitemap 설정에서 urls만 추출
|
||||
const sitemapUrls = response.sitemap?.urls || [];
|
||||
|
||||
config = {
|
||||
urls: sitemapUrls,
|
||||
cache: { sMaxAge: 3600, staleWhileRevalidate: 7200 }
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch sitemap config:', error);
|
||||
|
||||
// 에러 발생 시 빈 배열 반환
|
||||
config = {
|
||||
urls: [],
|
||||
cache: { sMaxAge: 3600, staleWhileRevalidate: 7200 }
|
||||
};
|
||||
}
|
||||
|
||||
setHeader(event, "Content-Type", "application/xml; charset=utf-8");
|
||||
|
||||
// 캐시 헤더 (CDN 친화)
|
||||
const sMax = config.cache?.sMaxAge ?? 3600;
|
||||
const swr = config.cache?.staleWhileRevalidate ?? 7200;
|
||||
setHeader(event, "Cache-Control", `public, s-maxage=${sMax}, stale-while-revalidate=${swr}`);
|
||||
|
||||
// XML 생성
|
||||
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
${config.urls.map(url => ` <url>
|
||||
<loc>${url.loc}</loc>
|
||||
${url.lastmod ? ` <lastmod>${url.lastmod}</lastmod>` : ''}
|
||||
${url.changefreq ? ` <changefreq>${url.changefreq}</changefreq>` : ''}
|
||||
${url.priority ? ` <priority>${url.priority}</priority>` : ''}
|
||||
</url>`).join('\n')}
|
||||
</urlset>`;
|
||||
|
||||
return xml;
|
||||
});
|
||||
Reference in New Issue
Block a user