
关于
在 Expo Router 中使用 EAS Hosting 创建 API 路由的指南。
name: expo-api-routes description: 在 Expo Router 中使用 EAS Hosting 创建 API 路由的指南 risk: unknown source: community version: 1.0.0 license: MIT
何时使用 API 路由
在以下情况使用 API 路由:
- 服务端密钥 — API 密钥、数据库凭据或绝不能到达客户端的令牌
- 数据库操作 — 不应暴露的直接数据库查询
- 第三方 API 代理 — 调用外部服务(OpenAI、Stripe 等)时隐藏 API 密钥
- 服务端验证 — 数据库写入前验证数据
- Webhook 端点 — 接收来自 Stripe 或 GitHub 等服务的回调
- 速率限制 — 在服务器层面控制访问
- 重计算 — 卸载在移动端会很慢的处理
何时不使用 API 路由
在以下情况避免使用 API 路由:
- 数据已经是公开的 — 改用直接 fetch 公共 API
- 不需要密钥 — 静态数据或客户端安全操作
- 需要实时更新 — 使用 WebSockets 或 Supabase Realtime 等服务
- 简单 CRUD — 考虑 Firebase、Supabase 或 Convex 等托管后端
- 文件上传 — 使用直接上传到存储(S3 预签名 URL、Cloudflare R2)
- 仅认证 — 改用 Clerk、Auth0 或 Firebase Auth
文件结构
API 路由位于 app 目录中,使用 +api.ts 后缀:
app/
api/
hello+api.ts → GET /api/hello
users+api.ts → /api/users
users/[id]+api.ts → /api/users/:id
(tabs)/
index.tsx
基本 API 路由
// app/api/hello+api.ts
export function GET(request: Request) {
return Response.json({ message: "Hello from Expo!" });
}
HTTP 方法
为每个 HTTP 方法导出命名函数:
// app/api/items+api.ts
export function GET(request: Request) {
return Response.json({ items: [] });
}
export async function POST(request: Request) {
const body = await request.json();
return Response.json({ created: body }, { status: 201 });
}
export async function PUT(request: Request) {
const body = await request.json();
return Response.json({ updated: body });
}
export async function DELETE(request: Request) {
return new Response(null, { status: 204 });
}
动态路由
// app/api/users/[id]+api.ts
export function GET(request: Request, { id }: { id: string }) {
return Response.json({ userId: id });
}
请求处理
查询参数
export function GET(request: Request) {
const url = new URL(request.url);
const page = url.searchParams.get("page") ?? "1";
const limit = url.searchParams.get("limit") ?? "10";
return Response.json({ page, limit });
}
请求头
export function GET(request: Request) {
const auth = request.headers.get("Authorization");
if (!auth) {
return Response.json({ error: "Unauthorized" }, { status: 401 });
}
return Response.json({ authenticated: true });
}
JSON 请求体
export async function POST(request: Request) {
const { email, password } = await request.json();
if (!email || !password) {
return Response.json({ error: "Missing fields" }, { status: 400 });
}
return Response.json({ success: true });
}
环境变量
使用 process.env 获取服务端密钥:
// app/api/ai+api.ts
export async function POST(request: Request) {
const { prompt } = await request.json();
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
},
body: JSON.stringify({
model: "gpt-4",
messages: [{ role: "user", content: prompt }],
}),
});
const data = await response.json();
return Response.json(data);
}
设置环境变量:
- 本地:创建
.env文件(永远不要提交) - EAS Hosting:使用
eas env:create或 Expo 仪表板
CORS 请求头
为跨域请求添加 CORS 头:
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
};
兼容工具
Claude CodeCursor
标签
移动端