Gọi từ route handler phía server (app/api/chat/route.ts) hoặc server action, không bao giờ gọi trực tiếp từ trình duyệt.
Lý do:
- API key. Bất cứ biến nào có tiền tố NEXT_PUBLIC_ đều nằm trong bundle mà người dùng xem được. Key lộ nghĩa là người khác tiêu tiền trên tài khoản của bạn.
- Kiểm soát. Chỉ ở server bạn mới kiểm tra được đăng nhập, hạn mức theo người dùng, độ dài input, và ghi log chi phí.
- Prompt. System prompt là tài sản sản phẩm; gọi từ client là công khai nó.
ts
// app/api/chat/route.ts
export async function POST(req: Request) {
const session = await auth()
if (!session) return new Response('Unauthorized', { status: 401 })
const { messages } = await req.json()
const stream = await callModel({ messages, apiKey: process.env.LLM_API_KEY })
return new Response(stream, { headers: { 'Content-Type': 'text/event-stream' } })
}Client chỉ biết endpoint nội bộ /api/chat.
Muốn đổi nhà cung cấp hay đổi model, bạn sửa một chỗ ở server, phía client không đổi dòng nào.