Add comprehensive CORS fix guide

This commit is contained in:
donald
2025-12-04 00:07:38 +08:00
parent bf475d16c1
commit c7b229dc93

366
CORS_FIX_GUIDE.md Normal file
View File

@@ -0,0 +1,366 @@
# CORS 錯誤解決方案
## 🔴 您遇到的錯誤
### 錯誤訊息 1: CORS Policy
```
Access to fetch at 'https://api.anthropic.com/v1/messages' from origin 'http://127.0.0.1:5000'
has been blocked by CORS policy: Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
```
### 錯誤訊息 2: Storage Access
```
Uncaught (in promise) Error: Access to storage is not allowed from this context.
```
### 錯誤訊息 3: Failed to Fetch
```
POST https://api.anthropic.com/v1/messages net::ERR_FAILED
TypeError: Failed to fetch
```
## 🤔 為什麼會發生這些錯誤?
### 1. **CORS跨來源資源共用限制**
- 瀏覽器的安全機制,防止網頁向不同來源的伺服器發送請求
- Anthropic API 不允許直接從瀏覽器呼叫(沒有設定 CORS 標頭)
- 這是為了保護 API 金鑰不被暴露
### 2. **API 金鑰安全問題**
```javascript
// ❌ 危險!前端直接呼叫會暴露 API 金鑰
const apiKey = 'sk-ant-xxxxx'; // 所有人都能看到
fetch('https://api.anthropic.com/v1/messages', {
headers: { 'x-api-key': apiKey }
});
```
### 3. **Storage 限制**
- 使用 `file://` 協定開啟的 HTML 檔案無法使用 localStorage
- 必須透過 HTTP 伺服器運行
## ✅ 正確的解決方案
### 架構圖
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ │ │ │ │ │
│ 前端 │ ─────▶ │ 後端 │ ─────▶ │ Claude API │
│ (瀏覽器) │ HTTP │ (Express) │ HTTPS │ (Anthropic)│
│ │ │ │ │ │
└─────────────┘ └─────────────┘ └─────────────┘
│ API 金鑰
│ 安全儲存
```
### 步驟 1: 安裝依賴
```bash
npm install
```
這會安裝:
- `express` - Web 伺服器框架
- `cors` - CORS 中介層
- `axios` - HTTP 客戶端
- `dotenv` - 環境變數管理
- 其他依賴...
### 步驟 2: 設定環境變數
編輯 [.env](.env) 檔案,加入您的 Claude API 金鑰:
```env
# Claude API
CLAUDE_API_KEY=sk-ant-api03-xxxxxxxxxxxxx
CLAUDE_API_URL=https://api.anthropic.com/v1
CLAUDE_MODEL=claude-3-5-sonnet-20241022
```
⚠️ **重要**`.env` 檔案已被 `.gitignore` 排除,不會被提交到 Git
### 步驟 3: 啟動後端伺服器
```bash
# 開發模式(自動重啟)
npm run dev
# 或生產模式
npm start
```
您應該會看到:
```
==================================================
🚀 HR Performance System API Server
==================================================
📡 Server running on: http://localhost:3000
🌍 Environment: development
📅 Started at: 2025-12-03 ...
==================================================
📚 Available endpoints:
GET / - API information
GET /health - Health check
POST /api/llm/test/* - Test LLM connections
POST /api/llm/generate - Generate content with LLM
✨ Server is ready to accept connections!
```
### 步驟 4: 測試 API
開啟瀏覽器訪問:
```
http://localhost:3000/api-proxy-example.html
```
或使用 curl 測試:
```bash
# 測試 Claude 連線
curl -X POST http://localhost:3000/api/llm/test/claude
# 生成內容
curl -X POST http://localhost:3000/api/llm/generate \
-H "Content-Type: application/json" \
-d '{
"prompt": "介紹 HR 績效評核系統",
"provider": "claude",
"options": {
"temperature": 0.7,
"maxTokens": 200
}
}'
```
## 📝 前端程式碼範例
### ❌ 錯誤的做法(直接呼叫)
```javascript
// 不要這樣做!會被 CORS 阻擋
async function callClaudeAPI() {
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'sk-ant-xxxxx', // ❌ API 金鑰暴露!
'anthropic-version': '2023-06-01'
},
body: JSON.stringify({
model: 'claude-3-5-sonnet-20241022',
messages: [{ role: 'user', content: 'Hello' }]
})
});
}
```
### ✅ 正確的做法(透過後端代理)
```javascript
// 透過後端 API 呼叫
async function generateContent(prompt) {
try {
const response = await fetch('http://localhost:3000/api/llm/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: prompt,
provider: 'claude',
options: {
temperature: 0.7,
maxTokens: 2000
}
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
if (result.success) {
console.log('生成的內容:', result.content);
return result.content;
} else {
throw new Error(result.error?.message || '生成失敗');
}
} catch (error) {
console.error('錯誤:', error);
// 顯示錯誤訊息給使用者
showErrorModal({
title: 'API 錯誤',
message: error.message
});
}
}
// 使用範例
generateContent('請介紹 HR 績效評核系統的四卡循環');
```
## 🎯 API 端點說明
### 測試連線
```javascript
// 測試 Claude API
POST http://localhost:3000/api/llm/test/claude
// 測試所有 LLM
POST http://localhost:3000/api/llm/test/all
// 回應格式
{
"success": true,
"message": "Claude API connection successful",
"provider": "claude",
"model": "claude-3-5-sonnet-20241022"
}
```
### 生成內容
```javascript
POST http://localhost:3000/api/llm/generate
Content-Type: application/json
{
"prompt": "你的提示內容",
"provider": "claude", // 可選: claude, gemini, deepseek, openai
"options": {
"temperature": 0.7, // 可選: 0.0-1.0
"maxTokens": 2000 // 可選: 最大生成長度
}
}
// 回應格式
{
"success": true,
"content": "生成的內容...",
"provider": "claude"
}
```
### Help Me AI智能填寫
```javascript
POST http://localhost:3000/api/llm/help-me-fill
Content-Type: application/json
{
"cardType": "performance",
"cardId": "PF-2024-001",
"filledFields": {
"kra1_title": "產品上市時程",
"kra1_weight": 40
},
"emptyFields": [
"kra1_output",
"kra1_self_note"
],
"context": {
"roleCard": {...},
"competencyCard": {...}
}
}
// 回應格式
{
"success": true,
"filledCount": 2,
"suggestions": {
"kra1_output": "Q1 完成 MVP 開發...",
"kra1_self_note": "超額達成目標..."
}
}
```
## 🔒 安全性考量
### 1. API 金鑰保護
- ✅ 儲存在 `.env` 檔案
- ✅ 不提交到 Git已在 `.gitignore` 中)
- ✅ 只在後端使用
- ❌ 絕不在前端程式碼中暴露
### 2. CORS 設定
```javascript
// server.js 中的 CORS 設定
app.use(cors({
origin: process.env.FRONTEND_URL || '*', // 生產環境應限制來源
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true
}));
```
### 3. 錯誤處理
- 統一的錯誤格式
- 不洩露敏感資訊
- 記錄錯誤日誌
## 🐛 常見問題
### Q1: 為什麼還是顯示 CORS 錯誤?
**A:** 確認以下事項:
1. 後端伺服器是否正在運行?(`npm run dev`
2. 前端是否呼叫正確的 API 地址?(`http://localhost:3000`
3. 瀏覽器是否快取了舊的錯誤?(清除快取或使用無痕模式)
### Q2: API 回傳 "Claude API key not configured"
**A:** 檢查:
1. `.env` 檔案中是否設定了 `CLAUDE_API_KEY`
2. 環境變數的值是否正確
3. 重新啟動伺服器以載入新的環境變數
### Q3: 連線超時
**A:** 可能原因:
1. 網路連線問題
2. API 金鑰無效
3. Anthropic 服務暫時無法使用
4. 超時設定太短(預設 30 秒)
### Q4: 如何在生產環境部署?
**A:** 部署步驟:
1. 設定環境變數(不要使用 `.env` 檔案)
2. 限制 CORS 來源為您的網域
3. 使用 HTTPS
4. 設定適當的速率限制
5. 記錄和監控 API 使用情況
## 📚 相關檔案
- [server.js](server.js) - Express 伺服器
- [routes/llm.routes.js](routes/llm.routes.js) - API 路由
- [services/llm.service.js](services/llm.service.js) - LLM 服務
- [config/llm.config.js](config/llm.config.js) - LLM 配置
- [utils/errorHandler.js](utils/errorHandler.js) - 錯誤處理
- [public/api-proxy-example.html](public/api-proxy-example.html) - 範例頁面
## 🎉 完成!
現在您可以安全地透過後端 API 呼叫 Claude 和其他 LLM 服務,不再有 CORS 錯誤!
如有任何問題,請參考:
- [README.md](README.md) - 專案說明
- [database/README.md](database/README.md) - 資料庫文件
- [docs/GITEA_SETUP.md](docs/GITEA_SETUP.md) - Git 設定
---
**最後更新**: 2025-12-03
**問題回報**: https://gitea.theaken.com/donald/hr-performance-system/issues