Svelte博客:如何禁止published: false的Markdown文章直接访问
问题描述
我用Markdown文件搭建了一个Svelte网站,需求是当文章frontmatter里有published: false时,该文章不发布且从列表中排除。目前已经修改api/posts/+server.js实现了列表过滤,但这类文章还是能通过直接链接访问,需要实现让它无法访问并返回404,该怎么操作?
现有代码如下:
- 工具函数
lib/utils/getPosts.js:
/*lib/utils/getPosts.js*/ // @ts-nocheck export const getMarkdownPosts = async () => { const allPostFiles = import.meta.glob('/src/content/posts/*.md') const iterablePostFiles = Object.entries(allPostFiles) const allPosts = await Promise.all( iterablePostFiles.map(async ([path, resolver]) => { const { metadata } = await resolver() const postPath = path.split('/').at(-1)?.replace('.md', '') return { meta: metadata, path: postPath, } }) ) return allPosts }
- 修改后的
api/posts/+server.js:
/*api/posts/+server.js*/ import { getMarkdownPosts } from '$lib/utils/getPosts' import { json } from '@sveltejs/kit' export const GET = async () => { const allPosts = await getMarkdownPosts() const sortedPosts = allPosts.sort((a, b) => { return new Date(b.meta.date) - new Date(a.meta.date) }).filter(post => post.meta.published === true) return json(sortedPosts) }
- 文章页面的load函数
blog/[slug]/+page.js:
/*blog/[slug]/+page.js*/ export async function load({ params }){ const post = await import(`../../../content/posts/${params.slug}.md`) const { title, date, categories, draft } = post.metadata const content = post.default return { content, title, date, categories } }
解决方案
要实现未发布文章无法直接访问,核心是在文章页面的加载逻辑中增加发布状态校验,结合SvelteKit的错误处理机制返回404,以下是具体实现步骤:
步骤1:修改文章页面的load函数
在加载文章时,先读取frontmatter中的published字段,若为false则抛出404错误。同时增加异常捕获,处理文件不存在的情况:
/*blog/[slug]/+page.js*/ import { error } from '@sveltejs/kit'; export async function load({ params }){ try { const post = await import(`../../../content/posts/${params.slug}.md`); const { title, date, categories, published } = post.metadata; const content = post.default; // 校验发布状态,未发布则返回404 if (published === false) { throw error(404, '文章未发布或不存在'); } return { content, title, date, categories }; } catch (err) { // 文件不存在或校验失败时返回404 throw error(404, '文章未发布或不存在'); } }
步骤2:(可选)统一校验逻辑到工具函数
如果需要在多个场景复用校验逻辑,可以给lib/utils/getPosts.js新增根据slug获取已发布文章的函数:
/*lib/utils/getPosts.js*/ // @ts-nocheck export const getMarkdownPosts = async () => { const allPostFiles = import.meta.glob('/src/content/posts/*.md'); const iterablePostFiles = Object.entries(allPostFiles); const allPosts = await Promise.all( iterablePostFiles.map(async ([path, resolver]) => { const { metadata } = await resolver(); const postPath = path.split('/').at(-1)?.replace('.md', ''); return { meta: metadata, path: postPath, }; }) ); return allPosts; }; // 新增:根据slug获取已发布的文章 export const getPublishedPostBySlug = async (slug) => { try { const post = await import(`../../content/posts/${slug}.md`); const { metadata, default: content } = post; if (metadata.published === false) { return null; } return { meta: metadata, content, slug }; } catch (err) { return null; } };
然后在blog/[slug]/+page.js中调用该工具函数:
/*blog/[slug]/+page.js*/ import { error } from '@sveltejs/kit'; import { getPublishedPostBySlug } from '$lib/utils/getPosts'; export async function load({ params }){ const post = await getPublishedPostBySlug(params.slug); if (!post) { throw error(404, '文章未发布或不存在'); } const { title, date, categories } = post.meta; return { content: post.content, title, date, categories }; }
步骤3:静态生成场景额外处理(若启用SSG)
如果网站使用静态生成,需要确保未发布文章不会被预渲染,在blog/[slug]/+page.js中添加getStaticPaths函数过滤路径:
/*blog/[slug]/+page.js*/ import { error } from '@sveltejs/kit'; import { getMarkdownPosts } from '$lib/utils/getPosts'; export async function getStaticPaths() { const allPosts = await getMarkdownPosts(); // 仅生成已发布文章的静态路径 const publishedPosts = allPosts.filter(post => post.meta.published === true); return { paths: publishedPosts.map(post => ({ params: { slug: post.path } })), fallback: 'blocking' // 根据需求选择false或blocking }; } export async function load({ params }){ const post = await import(`../../../content/posts/${params.slug}.md`); const { title, date, categories, published } = post.metadata; const content = post.default; if (published === false) { throw error(404, '文章未发布或不存在'); } return { content, title, date, categories }; }
内容的提问来源于stack exchange,提问作者Лео
相关产品推荐
相关产品推荐

