Why You Should Route Requests Through a Proxy Gateway
The most common approach indie developers take when adding AI features is calling the model API directly from the frontend. This has a fatal flaw: the API Key is either hardcoded into the frontend code, or the client has to change every time you switch models. I've seen a small team maintain three sets of calling logic in their frontend code just to integrate three models—every vendor switch required a release, and the whole back-and-forth took three days.
The way to compress that time down to half an hour is simple: write a proxy gateway in a Next.js Route Handler, so the frontend only talks to one stable internal endpoint, while vendor differences, key management, and logging all converge on the server side. Here's the before-and-after comparison:
| Item | Before (frontend direct) | After (Route Handler proxy) |
|---|---|---|
| API Key exposure risk | High, bundled into client | Zero exposure |
| Switching model vendors | Modify frontend + release, ~2 hrs/switch | Change one spot on server, ~5 min/switch |
| Usage tracking | Scattered across clients, manual aggregation | Unified server-side logging, real-time visibility |
| First-time integration of a new model | Half a day to a full day | Under 30 minutes |
For a one- or two-person team, these time savings are very real—especially when you're maintaining both a web app and a mini-program, the proxy pattern can cut your client-side code by more than half.
Step 1: Register and Get an API Key
This article uses ThisToken.AI as an example (it provides a unified OpenAI-compatible interface—one key can call multiple models). The process:
- Visit https://api.thistoken.ai/register to create an account;
- Go to the API Keys page in the console, create a new key, and store it securely;
- On the model list page, confirm the names of the models you want to call. I won't guess at pricing—refer to the official pricing page.
Step 2: Configure Environment Variables
Create .env.local in the project root (remember to add it to .gitignore):
THISTOKEN_API_KEY=sk-your-keyStep 3: Write the Route Handler
Create app/api/chat/route.ts:
import { NextRequest, NextResponse } from "next/server";
export async function POST(req: NextRequest) {
try {
const { messages, model } = await req.json();
const upstream = await fetch("https://api.thistoken.ai/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
// Key只存在于服务端,永不下发到浏览器
Authorization: `Bearer ${process.env.THISTOKEN_API_KEY}`,
},
body: JSON.stringify({
model: model ?? "gpt-4o-mini",
messages,
}),
});
if (!upstream.ok) {
const errText = await upstream.text();
return NextResponse.json(
{ error: `上游错误: ${upstream.status}`, detail: errText },
{ status: upstream.status }
);
}
const data = await upstream.json();
// 这里可以顺手记录用量:data.usage 里有 prompt_tokens / completion_tokens
console.log(
`[chat] model=${data.model} tokens=${data.usage?.total_tokens ?? "n/a"}`
);
return NextResponse.json({
content: data.choices?.[0]?.message?.content ?? "",
usage: data.usage,
});
} catch (e) {
return NextResponse.json({ error: "代理请求失败" }, { status: 500 });
}
}Note that https://api.thistoken.ai/v1 in the code is the base URL—all endpoints live under it, and it's compatible with OpenAI's request format, so any calling logic you've written before can basically be reused as-is.
Step 4: Call It from the Frontend
The frontend only needs to talk to your own /api/chat:
const res = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "帮我总结这段话" }],
}),
});
const { content } = await res.json();A Few Enhancements Worth Adding
1. Streaming responses (SSE). Add "stream": true, then pass upstream.body through to the client directly as a ReadableStream—time-to-first-token usually drops from several seconds to under one second:
return new NextResponse(upstream.body, {
headers: { "Content-Type": "text/event-stream" },
});2. Unified timeouts and retries. Use AbortSignal.timeout(30000) to control upstream timeouts, so one slow request doesn't drag down your entire function instance.
3. Persist usage data. Replace that console.log line with a database write—that's the simplest possible starting point for usage auditing, so you won't have to dig through logs to reconcile bills later.
Common Pitfalls
- Route file in the wrong place: It must be
app/api/xxx/route.ts, exporting lowercase functions matching the HTTP methods, likePOST/GET. - Environment variables not taking effect: After modifying
.env.local, you need to restart the dev server. - Passing the key through to the frontend: Under no circumstances should you return
THISTOKEN_API_KEYin a response body or inject it into client components. - Error handling that's too thin: When the upstream returns 429 or 5xx, give the frontend a clear error code—it saves a lot of debugging time.
Summary
The proxy gateway pattern requires a one-time investment of less than an hour, and in return you get: zero key exposure, switching vendors goes from a "release-level" operation to changing a single string, and usage data is centralized and visible in one place. For indie developers, this is one of those rare architectural decisions with small costs and compounding returns.
If you haven't registered for ThisToken.AI yet, head over to https://api.thistoken.ai/register to create an account. Once you have your key, run the code above—within half an hour you'll see your first response.
---
Ready to try it yourself? Sign up at https://api.thistoken.ai/register to get your API key and start building.
Token.AI を試してみませんか?
プロジェクトレベルの API Key を作成し、コンソールでチャネルを有効にして、ルーティング、予算、監査ログを設定しましょう。
注册 ThisToken.AI 并获取 API Key