运维部署
在 Expo 网页/API 路由需要部署到 EAS…
把 Expo 网页应用和 Expo Router API 路由部署到 EAS Hosting(Cloudflare Workers),并编写、测试、保护 +api.ts 路由和配置部署环境。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 Expo 网页/API 路由需要部署特定
解决思路
- 在 app 目录用 +api.ts 后缀定义服务端 API 路由:app/api/hello+api.ts 对应 GET /api/hello,app/api/users+api.ts 对应 /api/users,app/api/users/[id]+api.ts 对应 /api/users/:id。
- 基础路由写法:export function GET(request: Request) { return Response.json({ message: 'Hello from Expo!' }); }。
- 按 HTTP 方法导出同名函数:export function GET、export async function POST、export async function PUT、export async function DELETE;POST 中 await request.json() 并用 { status: 201 } 返回 201,DELETE 返回 new Response(null, { status: 204 })。
- 动态路由写法:export function GET(request: Request, { id }: { id: string }) { return Response.json({ userId: id }); }。
- 读取查询参数:const url = new URL(request.url); const page = url.searchParams.get('page') ?? '1'; const limit = url.searchParams.get('limit') ?? '10'; 然后 Response.json({ page, limit })。
- 读取请求头:const auth = request.headers.get('Authorization'); 若无 auth 返回 Response.json({ error: 'Unauthorized' }, { status: 401 })。
- 读取 JSON 请求体:const { email, password } = await request.json(); 校验缺失字段后返回 Response.json({ error: 'Missing fields' }, { status: 400 })。
- 服务端使用 process.env 读取密钥:例如 Authorization: `Bearer ${process.env.OPENAI_API_KEY}`;本地创建 .env 且不要提交,EAS Hosting 上用 eas env:create 或 Expo dashboard 设置。
- 为 Web 客户端添加 CORS:定义 corsHeaders 包含 Access-Control-Allow-Origin: '*'、Access-Control-Allow-Methods: 'GET, POST, PUT, DELETE, OPTIONS'、Access-Control-Allow-Headers: 'Content-Type, Authorization';导出 OPTIONS 返回 new Response(null, { headers: corsHeaders }),其他方法返回时也带上 headers: corsHeaders。
- 错误处理:在 API 路由中用 try/catch,catch 中 console.error('API error:', error) 并返回 Response.json({ error: 'Internal server error' }, { status: 500 })。
- 本地测试:运行 npx expo serve,在 http://localhost:8081 获得完整 API 路由支持;用 curl http://localhost:8081/api/hello 以及 curl -X POST ... -H 'Content-Type: application/json' -d '...' 测试。
- 部署前准备:npm install -g eas-cli;eas login。
- 部署:先 npx expo export -p web 导出 Web 包(包含 API 路由),再 npx eas-cli@latest deploy 部署预览(PR 风格 URL),或 npx eas-cli@latest deploy --prod 部署生产;eas deploy 会同时发布 Web 包和 Expo Router API 路由。
- 生产环境变量:eas env:create --name OPENAI_API_KEY --value sk-xxx --environment production,或在 Expo dashboard 配置。
- 自定义域名:在 eas.json 或 Expo dashboard 中配置。
- 用 EAS Workflows 自动部署:创建 .eas/workflows/deploy.yml,name: Deploy,on: push: branches: [main],jobs.deploy_web.type: deploy,params.prod: true;PR 预览用 on: pull_request: types: [opened, synchronize],params.prod: false;更复杂的 YAML 编写/校验用 eas-workflows 技能。
- 适配 EAS Hosting 的 Cloudflare Workers 运行时:没有 Node.js 文件系统(fs 不可用),没有原生 Node 模块,CPU 密集任务约 30 秒超时,不能持久连接(WebSocket 需 Durable Objects),但 fetch 可用。
- 优先使用 Web API:用 Web Crypto(crypto.subtle.digest('SHA-256', new TextEncoder().encode('data')))替代 Node crypto,用 fetch 替代 node-fetch,用 Response/Request 返回结果。
- 因文件系统不可用,使用云数据库:Cloudflare D1、Turso、PlanetScale、Supabase、Neon。Turso 示例:import { createClient } from '@libsql/client/web'; const db = createClient({ url: process.env.TURSO_URL!, authToken: process.env.TURSO_AUTH_TOKEN! }); 在 GET 中 const result = await db.execute('SELECT * FROM users'); return Response.json(result.rows)。
- 从客户端调用 API 路由:const response = await fetch('/api/hello'); const data = await response.json(); 带 body 时 fetch('/api/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'John' }) })。
- 认证中间件模式:在 utils/auth.ts 写 requireAuth(request),读取 Authorization 并去掉 'Bearer ',无 token 时 throw new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401, headers: { 'Content-Type': 'application/json' } }),验证 token 后返回 { userId: '123' };在受保护路由中 import 并 await requireAuth(request)。
- 代理外部 API 模式:app/api/weather+api.ts 中从 URL 读取 city,fetch 外部 API 时带上 process.env.WEATHER_API_KEY,然后 Response.json(await response.json())。
- 遵守规则:绝不在客户端代码暴露 API key 或 secret;始终校验和清理用户输入;使用正确 HTTP 状态码(200、201、400、401、404、500);用 try/catch 优雅处理错误;每个 endpoint 只负责一件事;使用 TypeScript;在服务端记录错误便于调试。
- 提交反馈:遇到错误或过时信息时运行 npx --yes submit-expo-feedback@latest --category skills --subject "eas-hosting" "<actionable feedback>",只在有具体可操作内容时提交;若 AI 代理反复失败或用户被迫接管,加载 expo-skill-feedback 技能并按 eval-candidate 流程处理。
适用边界 · 注意事项
- 不用于原生构建或应用商店发布;这类任务用 eas-app-stores 技能。
- 不需要服务端密钥、数据库操作、第三方 API 代理、服务端校验、Webhook、限流或重计算时,不要用 API 路由:已公开数据直接 fetch,实时更新用 WebSocket/Supabase Realtime,简单 CRUD 用 Firebase/Supabase/Convex,文件上传用 S3 预签名 URL/Cloudflare R2 直传,仅认证用 Clerk/Auth0/Firebase Auth。
- 需要 Node.js 文件系统、原生 Node 模块、超过约 30 秒的 CPU 任务、持久 WebSocket 连接,或无法使用 EAS 付费服务时,不适合 EAS Hosting/Cloudflare Workers 运行时。