You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在最新版SvelteKit中实现基于Accept头的路由穿透?

在SvelteKit中基于Accept头实现通用API路由方案

需求说明

需要实现一套依赖Accept请求头的通用API路由,具体规则:

  • GET /[schema] - 返回包含{schema}条目列表的HTML页面
  • GET /[schema](携带Accept: application/json头)- 返回{schema}条目列表的JSON格式数据
  • POST /[schema](携带Accept: application/json头)- 保存{schema}条目
  • GET /[schema]/[id] - 返回包含{schema}条目的HTML详情页
  • GET /[schema]/[id](携带Accept: application/json头)- 返回{schema}条目的JSON格式数据

限制条件

  • 不能使用/[schema]/+server.js直接响应所有请求,需仅过滤带Accept: application/json的请求
  • 不能/不愿使用中间件(搭配node/vite开发服务器),避免影响+page.js的load函数使用相对URL
  • 原路由穿透功能已移除,URL matchers无法获取请求头且不支持异步

实现方案

核心思路是通过+server.js校验Accept头处理API请求,同时页面的load函数携带指定头请求同一路由获取数据,既满足API的头校验要求,又不影响页面路由的正常渲染。

1. 通用列表路由(/[schema])

src/routes/[schema]/+page.svelte

HTML页面渲染组件,接收load函数返回的数据:

<script>
  export let data;
</script>

<h1>{$params.schema} 列表</h1>
<ul>
  {#each data.items as item}
    <li><a href="/{$params.schema}/{item.id}">{item.name}</a></li>
  {/each}
</ul>

src/routes/[schema]/+page.js

页面数据加载逻辑,携带Accept: application/json头请求同一路由获取JSON数据:

/** @type {import('./$types').PageLoad} */
export async function load({ fetch, params }) {
  const res = await fetch(`/${params.schema}`, {
    headers: {
      Accept: 'application/json'
    }
  });
  return {
    data: await res.json()
  };
}

src/routes/[schema]/+server.js

API请求处理逻辑,仅当Accept头包含application/json时响应,否则返回404交由页面路由处理:

import { error } from '@sveltejs/kit';

/** @type {import('./$types').RequestHandler} */
export async function GET({ request, params }) {
  const acceptHeader = request.headers.get('Accept');
  if (!acceptHeader?.includes('application/json')) {
    throw error(404, 'Not Found');
  }

  // 替换为实际业务逻辑:从数据库获取{schema}列表
  const items = [
    { id: 1, name: `${params.schema} 条目1` },
    { id: 2, name: `${params.schema} 条目2` }
  ];
  return new Response(JSON.stringify({ items }), {
    headers: {
      'Content-Type': 'application/json'
    }
  });
}

/** @type {import('./$types').RequestHandler} */
export async function POST({ request, params }) {
  const acceptHeader = request.headers.get('Accept');
  if (!acceptHeader?.includes('application/json')) {
    throw error(404, 'Not Found');
  }

  // 替换为实际业务逻辑:解析请求体并保存数据
  const body = await request.json();
  return new Response(JSON.stringify({ ...body, id: Date.now() }), {
    headers: {
      'Content-Type': 'application/json'
    },
    status: 201
  });
}

2. 详情路由(/[schema]/[id])

src/routes/[schema]/[id]/+page.svelte

详情页渲染组件:

<script>
  export let data;
</script>

<h1>{$params.schema} 详情</h1>
<p>ID: {data.item.id}</p>
<p>名称: {data.item.name}</p>
<a href="/{$params.schema}">返回列表</a>

src/routes/[schema]/[id]/+page.js

详情页数据加载逻辑:

/** @type {import('./$types').PageLoad} */
export async function load({ fetch, params }) {
  const res = await fetch(`/${params.schema}/${params.id}`, {
    headers: {
      Accept: 'application/json'
    }
  });
  return {
    data: await res.json()
  };
}

src/routes/[schema]/[id]/+server.js

详情API处理逻辑:

import { error } from '@sveltejs/kit';

/** @type {import('./$types').RequestHandler} */
export async function GET({ request, params }) {
  const acceptHeader = request.headers.get('Accept');
  if (!acceptHeader?.includes('application/json')) {
    throw error(404, 'Not Found');
  }

  // 替换为实际业务逻辑:根据ID从数据库获取条目
  const item = { id: params.id, name: `${params.schema} 条目${params.id}` };
  return new Response(JSON.stringify({ item }), {
    headers: {
      'Content-Type': 'application/json'
    }
  });
}

方案说明

  • 用户直接访问/[schema]时,SvelteKit优先匹配+page.svelte渲染HTML页面,+page.js中的fetch会调用同一路由的+server.js(因携带指定头,API逻辑正常响应JSON)
  • 外部客户端携带Accept: application/json头请求时,+server.js直接返回JSON;未携带指定头时返回404,符合仅处理API请求的需求
  • 该方式既规避了中间件的问题,又利用+server.js实现请求头校验,同时页面load函数可正常使用相对URL

内容的提问来源于stack exchange,提问作者bytesnz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 03:07:43