Nuxt 3 / 4 用 Server API 做代理與轉發
整理 Nuxt 3 與 Nuxt 4 使用 server/api 轉發第三方 API 的方式,可以避免瀏覽器 CORS 問題、隱藏 API Key,也能在伺服器端加入快取。
W
Nuxt 2 時期常使用 @nuxtjs/proxy 把 Nuxt 當成代理伺服器來解決 CORS。
到了 Nuxt 3,Nuxt 已經內建 Nitro Server;Nuxt 4 也延續相同架構,所以不一定需要另外安裝 proxy 套件。
可以簡單理解成:
瀏覽器
↓
自己的 Nuxt API
↓
第三方 API
前端不直接連第三方服務,而是先請 Nuxt Server 幫忙取得資料。
建立自己的 API
例如建立:
server/api/posts.ts
內容:
export default defineEventHandler(async () => {
return await $fetch('https://backend.example.com/posts')
})
Nuxt 會自動建立:
/api/posts
前端就可以:
const posts = await $fetch('/api/posts')
流程會變成:
瀏覽器
↓
/api/posts
↓
Nuxt Server
↓
https://backend.example.com/posts
瀏覽器只需要和自己的網站溝通。
第三方 API 的請求則由伺服器發出,因此不會受到瀏覽器 CORS 限制。
server/api 和 server/routes 的差別
Nuxt 3 與 Nuxt 4 都有:
server/
├── api/
└── routes/
放在:
server/api/posts.ts
網址會自動加上 /api:
/api/posts
放在:
server/routes/posts.ts
則會直接變成:
/posts
一般自己提供 API 給前端呼叫時,使用 server/api/ 就可以。
隱藏 API Key
如果第三方服務需要 API Key,不應該把金鑰放在前端。
例如:
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig(event)
return await $fetch('https://backend.example.com/posts', {
headers: {
Authorization: `Bearer ${config.apiKey}`
}
})
})
nuxt.config.ts:
export default defineNuxtConfig({
runtimeConfig: {
apiKey: ''
}
})
真正部署時再透過環境變數提供金鑰。
這樣瀏覽器只會看到:
/api/posts
不會拿到真正的 API Key。
可以順便加快取
如果第三方 API 不需要每次都重新取得,也可以在 Server API 加上快取:
export default defineCachedEventHandler(
async () => {
return await $fetch(
'https://backend.example.com/posts'
)
},
{
maxAge: 60 * 10
}
)
代表:
快取 10 分鐘
這種方式很適合:
天氣資料
公開資訊
新聞列表
第三方 API
更新頻率不高的資料
可以減少重複呼叫上游 API。
不要做成任意網址代理
不要寫成:
export default defineEventHandler(async (event) => {
const targetUrl = getQuery(event).url
return await $fetch(targetUrl)
})
例如讓使用者可以:
/api/proxy?url=https://任意網址
這等於讓任何人都能利用你的伺服器去請求其他網站。
可能造成:
被拿來當免費代理
浪費流量
攻擊其他服務
存取原本不該公開的內部網址
比較安全的方式是:
export default defineEventHandler(async () => {
return await $fetch(
'https://backend.example.com/posts'
)
})
也就是:
Nuxt Server 要連哪個 API,由你自己決定,不讓使用者直接傳完整網址。
如果真的需要動態參數,可以只接受明確的 ID 或固定範圍。
例如:
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, 'id')
return await $fetch(
`https://backend.example.com/posts/${id}`
)
})
Nuxt 2、3、4 差在哪?
| Nuxt 2 | Nuxt 3 | Nuxt 4 | |
|---|---|---|---|
| Server API | 需要另外處理 | Nitro 內建 | Nitro 內建 |
server/api/ | 沒有現在這套方式 | 支援 | 支援 |
| Proxy 套件 | 常用 @nuxtjs/proxy | 通常不需要 | 通常不需要 |
| 隱藏 API Key | 另外處理 | runtimeConfig | runtimeConfig |
| API 快取 | 另外處理 | Nitro Cache | Nitro Cache |
所以從 Nuxt 3 升到 Nuxt 4:
server/api/ 的基本使用方式沒有太大改變。
Nuxt 4 最大的目錄變化是在前端程式搬進:
app/
而:
server/
仍然留在專案根目錄。
小結
如果前端需要呼叫第三方 API,可以考慮:
前端
↓
Nuxt /api
↓
第三方 API
最基本的寫法:
// server/api/posts.ts
export default defineEventHandler(async () => {
return await $fetch(
'https://backend.example.com/posts'
)
})
這樣可以順便處理:
CORS
API Key
快取
資料整理
Nuxt 3 與 Nuxt 4 都可以使用相同做法。