Files
hr-performance-system/CORS_FIX_GUIDE.md
2025-12-04 00:07:38 +08:00

367 lines
9.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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