如何在API端点内正确发起同服务另一个端点的fetch请求?
已部署路径为 /api/metadata 的API端点,需要在同项目的另一个端点中请求该接口,初始实现代码如下:
export const get: RequestHandler = async (event) => { try { const res = await fetch(event.url + '/api/metadata') const body = await res.json() return { body }; } catch (error) { console.error(error); return { status: 500 }; } };
代码运行时抛出如下错误:
FetchError: request to http://localhost:3000/sitemap.xml/api/metadata failed, reason: connect ECONNREFUSED ::1:3000
将请求地址硬编码为 http://0.0.0.0:3000/api/metadata 时请求可正常响应。需求为不借助process.env.NODE_ENV、$app/env中的dev变量做环境条件判断,实现可在开发、生产环境通用的内部fetch逻辑。
不需要做任何环境判断,有三种通用实现方式,按推荐优先级排序:
1. 直接使用根相对路径发起请求(最推荐)
SvelteKit 对服务端上下文(API端点、服务端load函数)内的全局fetch做了原生封装,传入以/开头的内部路由路径时,运行时会直接匹配对应路由的处理函数执行,不会发起真实的对外HTTP网络请求,从根源上避免路径拼接错误、IPv4/IPv6解析失败、部署后域名变更等所有问题。
你只需要把原来的fetch行替换为如下代码即可:
const res = await fetch('/api/metadata')
该写法开发、生产环境完全通用,没有额外依赖,也没有网络开销。
2. 直接导入目标端点的处理函数调用
如果要完全跳过fetch层,也可以直接导入目标API端点导出的处理函数,传入当前event对象直接调用,性能和直接写内部逻辑一致,适合逻辑复用的场景:
// 路径按你项目中/api/metadata对应的实际路由文件位置调整 import { get as getMetadata } from '../routes/api/metadata.js'; export const get: RequestHandler = async (event) => { try { const metadataRes = await getMetadata(event); return { body: metadataRes.body }; } catch (error) { console.error(error); return { status: 500 }; } };
3. 规范构造绝对地址(仅当确实需要全路径URL时使用)
如果业务场景必须拿到完整的绝对请求地址,不要直接把event.url对象和路径做字符串拼接——event.url是当前请求的完整URL实例,字符串序列化后会带上当前请求的完整路径(比如访问/sitemap.xml时值为http://localhost:3000/sitemap.xml),直接拼接就会出现你遇到的/sitemap.xml/api/metadata错误路径。
正确做法是取event.url.origin(即协议+域名+端口的根地址),用URL类构造目标地址:
const targetUrl = new URL('/api/metadata', event.url.origin); const res = await fetch(targetUrl);
注意:该方案依然会走本地HTTP请求,可能遇到IPv6解析(localhost默认解析到
::1但服务绑定在IPv4地址)的问题,优先使用前两种方案。
内容的提问来源于stack exchange,提问作者John Winston

