🚀 快速安装

复制以下命令并运行,立即安装此 Skill:

npx @anthropic-ai/skills install expo/skills/expo-api-routes

💡 提示:需要 Node.js 和 NPM

何时使用应用程序编程接口路由

在以下情况下使用应用程序编程接口路由:

  • 服务器端密钥 — 绝不能到达客户端的应用程序编程接口密钥、数据库凭据或令牌
  • 数据库操作 — 不应暴露的直接数据库查询
  • 第三方应用程序编程接口代理 — 在调用外部服务(OpenAI、Stripe 等)时隐藏应用程序编程接口密钥
  • 服务器端验证 — 在写入数据库之前验证数据
  • 网络钩子端点 — 接收来自 Stripe 或 GitHub 等服务的回调
  • 速率限制 — 在服务器级别控制访问
  • 重型计算 — 卸载在移动设备上可能较慢的处理

何时不使用应用程序编程接口路由

避免在以下情况下使用应用程序编程接口路由:

  • 数据已经公开 — 改用直接获取公共应用程序编程接口
  • 无需密钥 — 静态数据或客户端安全操作
  • 需要实时更新 — 使用 WebSockets 或 Supabase Realtime 等服务
  • 简单的增删改查 — 考虑使用 Firebase、Supabase 或 Convex 等托管后端
  • 文件上传 — 使用直接上传到存储(S3 预签名网址、Cloudflare R2)
  • 仅身份验证 — 改用 Clerk、Auth0 或 Firebase Auth

文件结构

应用程序编程接口路由位于 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

基本应用程序编程接口路由

// app/api/hello+api.ts
export function GET(request: Request) {
  return Response.json({ message: "来自 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: "未授权" }, { 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: "缺少字段" }, { 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 托管:使用 eas env:create 或 Expo 仪表板

CORS 头

为 Web 客户端添加 CORS:

const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
  "Access-Control-Allow-Headers": "Content-Type, Authorization",
};

export function OPTIONS() {
  return new Response(null, { headers: corsHeaders });
}

export function GET() {
  return Response.json({ data: "value" }, { headers: corsHeaders });
}

错误处理

export async function POST(request: Request) {
  try {
    const body = await request.json();
    // 处理...
    return Response.json({ success: true });
  } catch (error) {
    console.error("应用程序编程接口错误:", error);
    return Response.json({ error: "内部服务器错误" }, { status: 500 });
  }
}

本地测试

启动带有应用程序编程接口路由的开发服务器:

npx expo serve

这将在 http://localhost:8081 启动一个完全支持应用程序编程接口路由的本地服务器。

使用 curl 测试:

curl http://localhost:8081/api/hello
curl -X POST http://localhost:8081/api/users -H "Content-Type: application/json" -d '{"name":"Test"}'

部署到 EAS 托管

前提条件

npm install -g eas-cli
eas login

部署

eas deploy

这将构建你的应用程序编程接口路由并将其部署到 EAS 托管(Cloudflare Workers)。

生产环境的环境变量

# 创建密钥
eas env:create --name OPENAI_API_KEY --value sk-xxx --environment production

# 或使用 Expo 仪表板

自定义域名

eas.json 或 Expo 仪表板中配置。

EAS 托管运行时(Cloudflare Workers)

应用程序编程接口路由在 Cloudflare Workers 上运行。主要限制:

缺失/受限的应用程序编程接口

  • 无 Node.js 文件系统fs 模块不可用
  • 无原生 Node 模块 — 使用 Web 应用程序编程接口或填充库
  • 执行时间有限 — 对于 CPU 密集型任务,超时时间为 30 秒
  • 无持久连接 — WebSockets 需要 Durable Objects
  • fetch 可用 — 使用标准 fetch 进行 HTTP 请求

改用 Web 应用程序编程接口

// 使用 Web Crypto 替代 Node crypto
const hash = await crypto.subtle.digest(
  "SHA-256",
  new TextEncoder().encode("data")
);

// 使用 fetch 替代 node-fetch
const response = await fetch("https://api.example.com");

// 使用 Response/Request(已可用)
return new Response(JSON.stringify(data), {
  headers: { "Content-Type": "application/json" },
});

数据库选项

由于文件系统不可用,请使用云数据库:

  • Cloudflare D1 — 边缘端的 SQLite
  • Turso — 分布式 SQLite
  • PlanetScale — 无服务器 MySQL
  • Supabase — 带 REST 应用程序编程接口的 Postgres
  • Neon — 无服务器 Postgres

Turso 示例:

// app/api/users+api.ts
import { createClient } from "@libsql/client/web";

const db = createClient({
  url: process.env.TURSO_URL!,
  authToken: process.env.TURSO_AUTH_TOKEN!,
});

export async function GET() {
  const result = await db.execute("SELECT * FROM users");
  return Response.json(result.rows);
}

从客户端调用应用程序编程接口路由

// 从 React Native 组件
const response = await fetch("/api/hello");
const data = await response.json();

// 带请求体
const response = await fetch("/api/users", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "John" }),
});

常见模式

身份验证中间件

// utils/auth.ts
export async function requireAuth(request: Request) {
  const token = request.headers.get("Authorization")?.replace("Bearer ", "");

  if (!token) {
    throw new Response(JSON.stringify({ error: "未授权" }), {
      status: 401,
      headers: { "Content-Type": "application/json" },
    });
  }

  // 验证令牌...
  return { userId: "123" };
}

// app/api/protected+api.ts
import { requireAuth } from "../../utils/auth";

export async function GET(request: Request) {
  const { userId } = await requireAuth(request);
  return Response.json({ userId });
}

代理外部应用程序编程接口

// app/api/weather+api.ts
export async function GET(request: Request) {
  const url = new URL(request.url);
  const city = url.searchParams.get("city");

  const response = await fetch(
    `https://api.weather.com/v1/current?city=${city}&key=${process.env.WEATHER_API_KEY}`
  );

  return Response.json(await response.json());
}

规则

  • 绝不在客户端代码中暴露应用程序编程接口密钥或密钥
  • 始终验证和清理用户输入
  • 使用正确的 HTTP 状态码(200、201、400、401、404、500)
  • 使用 try/catch 优雅地处理错误
  • 保持应用程序编程接口路由功能单一——每个端点一个职责
  • 使用 TypeScript 确保类型安全
  • 在服务器端记录错误以便调试

📄 原始文档

完整文档(英文):

https://skills.sh/expo/skills/expo-api-routes

💡 提示:点击上方链接查看 skills.sh 原始英文文档,方便对照翻译。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。