网页框架部署成功
This commit is contained in:
59
README.md
59
README.md
@@ -6,6 +6,11 @@
|
|||||||
|
|
||||||
InfoGenie 是一个前后端分离的多功能聚合应用,提供实时数据接口、休闲游戏、AI工具等丰富功能。
|
InfoGenie 是一个前后端分离的多功能聚合应用,提供实时数据接口、休闲游戏、AI工具等丰富功能。
|
||||||
|
|
||||||
|
### 🌐 部署环境
|
||||||
|
|
||||||
|
- **前端部署地址**: https://infogenie.shumengya.top
|
||||||
|
- **后端部署地址**: https://infogenie.api.shumengya.top
|
||||||
|
|
||||||
### 🏗️ 技术架构
|
### 🏗️ 技术架构
|
||||||
|
|
||||||
- **前端**: React + Styled Components + React Router
|
- **前端**: React + Styled Components + React Router
|
||||||
@@ -48,6 +53,60 @@ cd backend
|
|||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 🚢 部署指南
|
||||||
|
|
||||||
|
### 🖥️ 前端部署
|
||||||
|
|
||||||
|
1. 进入前端目录:`cd frontend/react-app`
|
||||||
|
2. 安装依赖:`npm install`
|
||||||
|
3. 构建生产环境应用:`npm run build`
|
||||||
|
4. 将 `build` 目录下的所有文件上传到前端服务器的网站根目录
|
||||||
|
|
||||||
|
也可以直接运行 `frontend/react-app/deploy.bat` 脚本进行构建。
|
||||||
|
|
||||||
|
### ⚙️ 后端部署
|
||||||
|
|
||||||
|
1. 进入后端目录:`cd backend`
|
||||||
|
2. 安装依赖:`pip install -r requirements.txt`
|
||||||
|
3. 配置环境变量或创建 `.env` 文件,包含以下内容:
|
||||||
|
```
|
||||||
|
MONGO_URI=你的MongoDB连接字符串
|
||||||
|
MAIL_USERNAME=你的邮箱地址
|
||||||
|
MAIL_PASSWORD=你的邮箱授权码
|
||||||
|
SECRET_KEY=你的应用密钥
|
||||||
|
SESSION_COOKIE_SECURE=True
|
||||||
|
```
|
||||||
|
4. 使用 Gunicorn 或 uWSGI 作为 WSGI 服务器启动应用:
|
||||||
|
```
|
||||||
|
gunicorn -w 4 -b 0.0.0.0:5000 "app:create_app()"
|
||||||
|
```
|
||||||
|
5. 配置反向代理,将 `https://infogenie.api.shumengya.top` 反向代理到后端服务
|
||||||
|
|
||||||
|
也可以参考 `backend/deploy.bat` 脚本中的部署说明。
|
||||||
|
|
||||||
|
### ⚙️ 配置说明
|
||||||
|
|
||||||
|
#### 前端配置
|
||||||
|
|
||||||
|
前端通过环境变量配置API基础URL:
|
||||||
|
|
||||||
|
- 开发环境:`.env.development` 文件中设置 `REACT_APP_API_URL=http://localhost:5000`
|
||||||
|
- 生产环境:`.env.production` 文件中设置 `REACT_APP_API_URL=https://infogenie.api.shumengya.top`
|
||||||
|
|
||||||
|
#### 后端配置
|
||||||
|
|
||||||
|
后端通过 `config.py` 和环境变量进行配置:
|
||||||
|
|
||||||
|
- MongoDB连接:通过环境变量 `MONGO_URI` 设置
|
||||||
|
- 邮件服务:通过环境变量 `MAIL_USERNAME` 和 `MAIL_PASSWORD` 设置
|
||||||
|
- CORS配置:在 `app.py` 中配置允许的前端域名
|
||||||
|
|
||||||
|
#### 60sAPI配置
|
||||||
|
|
||||||
|
60sAPI模块的静态文件位于 `frontend/60sapi` 目录,通过后端的静态文件服务提供访问。
|
||||||
|
|
||||||
|
各API模块的接口地址已配置为 `https://infogenie.api.shumengya.top/api/60s`。
|
||||||
|
|
||||||
#### 前端依赖
|
#### 前端依赖
|
||||||
```bash
|
```bash
|
||||||
cd frontend/react-app
|
cd frontend/react-app
|
||||||
|
|||||||
14
backend/.env.production
Normal file
14
backend/.env.production
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# 生产环境配置
|
||||||
|
|
||||||
|
# MongoDB配置
|
||||||
|
MONGO_URI=mongodb://用户名:密码@主机地址:端口/InfoGenie?authSource=admin
|
||||||
|
|
||||||
|
# 邮件配置
|
||||||
|
MAIL_USERNAME=your-email@qq.com
|
||||||
|
MAIL_PASSWORD=your-app-password
|
||||||
|
|
||||||
|
# 应用密钥
|
||||||
|
SECRET_KEY=infogenie-production-secret-key-2025
|
||||||
|
|
||||||
|
# 会话安全配置
|
||||||
|
SESSION_COOKIE_SECURE=True
|
||||||
@@ -31,7 +31,7 @@ def create_app():
|
|||||||
# 加载配置
|
# 加载配置
|
||||||
app.config.from_object(Config)
|
app.config.from_object(Config)
|
||||||
|
|
||||||
# 启用CORS跨域支持
|
# 启用CORS跨域支持(允许所有源)
|
||||||
CORS(app, supports_credentials=True)
|
CORS(app, supports_credentials=True)
|
||||||
|
|
||||||
# 初始化MongoDB
|
# 初始化MongoDB
|
||||||
@@ -182,6 +182,4 @@ def create_app():
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app = create_app()
|
app = create_app()
|
||||||
print("🚀 启动 InfoGenie 后端服务...")
|
print("🚀 启动 InfoGenie 后端服务...")
|
||||||
print("📡 API地址: http://localhost:5000")
|
app.run(debug=True, host='0.0.0.0', port=5002)
|
||||||
print("📚 文档地址: http://localhost:5000/api/health")
|
|
||||||
app.run(debug=True, host='0.0.0.0', port=5000)
|
|
||||||
|
|||||||
27
backend/deploy.bat
Normal file
27
backend/deploy.bat
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
@echo off
|
||||||
|
echo ===== 开始部署后端应用到生产环境 =====
|
||||||
|
|
||||||
|
cd /d "%~dp0"
|
||||||
|
|
||||||
|
echo 1. 安装依赖...
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
echo 2. 部署说明:
|
||||||
|
echo.
|
||||||
|
echo 请确保以下配置已完成:
|
||||||
|
echo 1. 在服务器上配置环境变量或创建 .env 文件,包含以下内容:
|
||||||
|
echo MONGO_URI=你的MongoDB连接字符串
|
||||||
|
echo MAIL_USERNAME=你的邮箱地址
|
||||||
|
echo MAIL_PASSWORD=你的邮箱授权码
|
||||||
|
echo SECRET_KEY=你的应用密钥
|
||||||
|
echo.
|
||||||
|
echo 3. 启动后端服务:
|
||||||
|
echo 在生产环境中,建议使用 Gunicorn 或 uWSGI 作为 WSGI 服务器
|
||||||
|
echo 示例命令:gunicorn -w 4 -b 0.0.0.0:5000 "app:create_app()"
|
||||||
|
echo.
|
||||||
|
echo 4. 配置反向代理:
|
||||||
|
echo 将 https://infogenie.api.shumengya.top 反向代理到后端服务
|
||||||
|
echo.
|
||||||
|
echo ===== 后端应用部署准备完成 =====
|
||||||
|
|
||||||
|
pause
|
||||||
@@ -73,10 +73,13 @@ def scan_directories():
|
|||||||
except:
|
except:
|
||||||
title = module_name
|
title = module_name
|
||||||
|
|
||||||
|
# 根据环境获取基础URL
|
||||||
|
base_url = 'https://infogenie.api.shumengya.top'
|
||||||
|
|
||||||
apis.append({
|
apis.append({
|
||||||
'title': title,
|
'title': title,
|
||||||
'description': f'{module_name}相关功能',
|
'description': f'{module_name}相关功能',
|
||||||
'link': f'http://localhost:5000/60sapi/{category_name}/{module_name}/index.html',
|
'link': f'{base_url}/60sapi/{category_name}/{module_name}/index.html',
|
||||||
'status': 'active',
|
'status': 'active',
|
||||||
'color': gradient_colors[i % len(gradient_colors)]
|
'color': gradient_colors[i % len(gradient_colors)]
|
||||||
})
|
})
|
||||||
|
|||||||
6
build_frontend.bat
Normal file
6
build_frontend.bat
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
@echo off
|
||||||
|
cd /d "e:\Python\InfoGenie\frontend\react-app"
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
npx serve -s build
|
||||||
|
pause
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// 本地后端API接口
|
// 本地后端API接口
|
||||||
const LOCAL_API_BASE = 'http://localhost:5000/api/60s';
|
const LOCAL_API_BASE = 'https://infogenie.api.shumengya.top/api/60s';
|
||||||
|
|
||||||
// API接口列表(备用)
|
// API接口列表(备用)
|
||||||
const API_ENDPOINTS = [
|
const API_ENDPOINTS = [
|
||||||
|
|||||||
2
frontend/react-app/.env.production
Normal file
2
frontend/react-app/.env.production
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# 生产环境API配置
|
||||||
|
REACT_APP_API_URL=https://infogenie.api.shumengya.top
|
||||||
@@ -44,6 +44,5 @@
|
|||||||
"last 1 firefox version",
|
"last 1 firefox version",
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
"proxy": "http://localhost:5000"
|
|
||||||
}
|
}
|
||||||
|
|||||||
48
frontend/react-app/public/sw.js
vendored
Normal file
48
frontend/react-app/public/sw.js
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// Service Worker for InfoGenie App
|
||||||
|
const CACHE_NAME = 'infogenie-cache-v1';
|
||||||
|
const urlsToCache = [
|
||||||
|
'/',
|
||||||
|
'/index.html',
|
||||||
|
'/manifest.json'
|
||||||
|
];
|
||||||
|
|
||||||
|
// 安装Service Worker
|
||||||
|
self.addEventListener('install', event => {
|
||||||
|
event.waitUntil(
|
||||||
|
caches.open(CACHE_NAME)
|
||||||
|
.then(cache => {
|
||||||
|
console.log('Opened cache');
|
||||||
|
return cache.addAll(urlsToCache);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 拦截请求并从缓存中响应
|
||||||
|
self.addEventListener('fetch', event => {
|
||||||
|
event.respondWith(
|
||||||
|
caches.match(event.request)
|
||||||
|
.then(response => {
|
||||||
|
// 如果找到缓存的响应,则返回缓存
|
||||||
|
if (response) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
return fetch(event.request);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 更新Service Worker
|
||||||
|
self.addEventListener('activate', event => {
|
||||||
|
const cacheWhitelist = [CACHE_NAME];
|
||||||
|
event.waitUntil(
|
||||||
|
caches.keys().then(cacheNames => {
|
||||||
|
return Promise.all(
|
||||||
|
cacheNames.map(cacheName => {
|
||||||
|
if (cacheWhitelist.indexOf(cacheName) === -1) {
|
||||||
|
return caches.delete(cacheName);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
13
frontend/react-app/src/index.js
vendored
13
frontend/react-app/src/index.js
vendored
@@ -9,3 +9,16 @@ root.render(
|
|||||||
<App />
|
<App />
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 注册Service Worker
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
navigator.serviceWorker.register('/sw.js')
|
||||||
|
.then(registration => {
|
||||||
|
console.log('ServiceWorker registration successful with scope: ', registration.scope);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('ServiceWorker registration failed: ', error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
7
frontend/react-app/src/pages/AiModelPage.js
vendored
7
frontend/react-app/src/pages/AiModelPage.js
vendored
@@ -3,7 +3,7 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { FiCpu, FiUser, FiExternalLink, FiArrowLeft } from 'react-icons/fi';
|
import { FiCpu, FiUser, FiExternalLink, FiArrowLeft } from 'react-icons/fi';
|
||||||
import { useUser } from '../contexts/UserContext';
|
import { useUser } from '../contexts/UserContext';
|
||||||
import axios from 'axios';
|
import api from '../utils/api';
|
||||||
|
|
||||||
const AiContainer = styled.div`
|
const AiContainer = styled.div`
|
||||||
min-height: calc(100vh - 140px);
|
min-height: calc(100vh - 140px);
|
||||||
@@ -262,7 +262,7 @@ const AiModelPage = () => {
|
|||||||
const fetchApps = async () => {
|
const fetchApps = async () => {
|
||||||
try {
|
try {
|
||||||
setLoadingApps(true);
|
setLoadingApps(true);
|
||||||
const response = await axios.get('/api/aimodelapp/scan-directories');
|
const response = await api.get('/api/aimodelapp/scan-directories');
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
setApps(response.data.apps);
|
setApps(response.data.apps);
|
||||||
} else {
|
} else {
|
||||||
@@ -278,7 +278,8 @@ const AiModelPage = () => {
|
|||||||
|
|
||||||
const handleLaunchApp = (app) => {
|
const handleLaunchApp = (app) => {
|
||||||
// 将相对路径转换为完整的服务器地址
|
// 将相对路径转换为完整的服务器地址
|
||||||
const fullLink = `http://localhost:5000${app.link}`;
|
const baseUrl = process.env.REACT_APP_API_URL || 'https://infogenie.api.shumengya.top';
|
||||||
|
const fullLink = `${baseUrl}${app.link}`;
|
||||||
setEmbeddedApp({ ...app, link: fullLink });
|
setEmbeddedApp({ ...app, link: fullLink });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
73
frontend/react-app/src/pages/Api60sPage.js
vendored
73
frontend/react-app/src/pages/Api60sPage.js
vendored
@@ -238,81 +238,26 @@ const Api60sPage = () => {
|
|||||||
// 从后端API获取目录结构
|
// 从后端API获取目录结构
|
||||||
const scanDirectories = async () => {
|
const scanDirectories = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('http://localhost:5000/api/60s/scan-directories');
|
// 使用环境变量中配置的API URL
|
||||||
|
const baseUrl = process.env.REACT_APP_API_URL || 'https://infogenie.api.shumengya.top';
|
||||||
|
const apiUrl = `${baseUrl}/api/60s/scan-directories`;
|
||||||
|
console.log('正在请求API目录结构:', apiUrl);
|
||||||
|
const response = await fetch(apiUrl);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('无法从后端获取目录结构,使用前端扫描方式');
|
console.warn('无法从后端获取目录结构:', error);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 前端扫描方式(备用)
|
// 前端扫描方式已移除
|
||||||
const frontendScan = async () => {
|
|
||||||
const categories = [];
|
|
||||||
|
|
||||||
for (const [categoryName, config] of Object.entries(categoryConfig)) {
|
|
||||||
const apis = [];
|
|
||||||
|
|
||||||
// 尝试访问已知的模块列表(只包含实际存在的模块)
|
|
||||||
const knownModules = {
|
|
||||||
'热搜榜单': ['抖音热搜榜'],
|
|
||||||
'日更资讯': [],
|
|
||||||
'实用功能': [],
|
|
||||||
'娱乐消遣': []
|
|
||||||
};
|
|
||||||
|
|
||||||
const moduleNames = knownModules[categoryName] || [];
|
// 只使用后端扫描
|
||||||
|
|
||||||
for (let i = 0; i < moduleNames.length; i++) {
|
|
||||||
const moduleName = moduleNames[i];
|
|
||||||
try {
|
|
||||||
const indexPath = `/60sapi/${categoryName}/${moduleName}/index.html`;
|
|
||||||
const fullUrl = `http://localhost:5000${indexPath}`;
|
|
||||||
const response = await fetch(fullUrl, { method: 'HEAD' });
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
// 获取页面标题
|
|
||||||
const htmlResponse = await fetch(fullUrl);
|
|
||||||
const html = await htmlResponse.text();
|
|
||||||
const titleMatch = html.match(/<title>(.*?)<\/title>/i);
|
|
||||||
const title = titleMatch ? titleMatch[1].trim() : moduleName;
|
|
||||||
|
|
||||||
apis.push({
|
|
||||||
title,
|
|
||||||
description: `${moduleName}相关功能`,
|
|
||||||
link: fullUrl,
|
|
||||||
status: 'active',
|
|
||||||
color: gradientColors[i % gradientColors.length]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// 忽略访问失败的模块
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (apis.length > 0) {
|
|
||||||
categories.push({
|
|
||||||
title: categoryName,
|
|
||||||
icon: config.icon,
|
|
||||||
color: config.color,
|
|
||||||
apis
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return categories;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 首先尝试后端扫描,失败则使用前端扫描
|
|
||||||
const backendResult = await scanDirectories();
|
const backendResult = await scanDirectories();
|
||||||
if (backendResult && backendResult.success) {
|
return backendResult && backendResult.success ? backendResult.categories || [] : [];
|
||||||
return backendResult.categories || [];
|
|
||||||
} else {
|
|
||||||
return await frontendScan();
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('扫描API模块时出错:', error);
|
console.error('扫描API模块时出错:', error);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { FiGrid, FiPlay, FiExternalLink, FiArrowLeft } from 'react-icons/fi';
|
import { FiGrid, FiPlay, FiExternalLink, FiArrowLeft } from 'react-icons/fi';
|
||||||
import axios from 'axios';
|
import api from '../utils/api';
|
||||||
|
|
||||||
const GameContainer = styled.div`
|
const GameContainer = styled.div`
|
||||||
min-height: calc(100vh - 140px);
|
min-height: calc(100vh - 140px);
|
||||||
@@ -233,7 +233,7 @@ const SmallGamePage = () => {
|
|||||||
const fetchGames = async () => {
|
const fetchGames = async () => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const response = await axios.get('/api/smallgame/scan-directories');
|
const response = await api.get('/api/smallgame/scan-directories');
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
setGames(response.data.games);
|
setGames(response.data.games);
|
||||||
} else {
|
} else {
|
||||||
@@ -249,7 +249,8 @@ const SmallGamePage = () => {
|
|||||||
|
|
||||||
const handlePlayGame = (game) => {
|
const handlePlayGame = (game) => {
|
||||||
// 将相对路径转换为完整的服务器地址
|
// 将相对路径转换为完整的服务器地址
|
||||||
const fullLink = `http://localhost:5000${game.link}`;
|
const baseUrl = process.env.REACT_APP_API_URL || 'https://infogenie.api.shumengya.top';
|
||||||
|
const fullLink = `${baseUrl}${game.link}`;
|
||||||
setEmbeddedGame({ ...game, link: fullLink });
|
setEmbeddedGame({ ...game, link: fullLink });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
39
frontend/react-app/src/utils/api.js
vendored
39
frontend/react-app/src/utils/api.js
vendored
@@ -3,7 +3,7 @@ import toast from 'react-hot-toast';
|
|||||||
|
|
||||||
// 创建axios实例
|
// 创建axios实例
|
||||||
const api = axios.create({
|
const api = axios.create({
|
||||||
baseURL: process.env.REACT_APP_API_URL || '/api',
|
baseURL: process.env.REACT_APP_API_URL || 'https://infogenie.api.shumengya.top',
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
withCredentials: true, // 支持携带cookie
|
withCredentials: true, // 支持携带cookie
|
||||||
headers: {
|
headers: {
|
||||||
@@ -11,6 +11,9 @@ const api = axios.create({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 打印当前使用的API URL,便于调试
|
||||||
|
console.log('API Base URL:', process.env.REACT_APP_API_URL || 'https://infogenie.api.shumengya.top');
|
||||||
|
|
||||||
// 请求拦截器
|
// 请求拦截器
|
||||||
api.interceptors.request.use(
|
api.interceptors.request.use(
|
||||||
(config) => {
|
(config) => {
|
||||||
@@ -44,63 +47,63 @@ api.interceptors.response.use(
|
|||||||
// 认证相关API
|
// 认证相关API
|
||||||
export const authAPI = {
|
export const authAPI = {
|
||||||
// 发送验证码
|
// 发送验证码
|
||||||
sendVerification: (data) => api.post('/auth/send-verification', data),
|
sendVerification: (data) => api.post('/api/auth/send-verification', data),
|
||||||
|
|
||||||
// 验证验证码
|
// 验证验证码
|
||||||
verifyCode: (data) => api.post('/auth/verify-code', data),
|
verifyCode: (data) => api.post('/api/auth/verify-code', data),
|
||||||
|
|
||||||
// 登录
|
// 登录
|
||||||
login: (credentials) => api.post('/auth/login', credentials),
|
login: (credentials) => api.post('/api/auth/login', credentials),
|
||||||
|
|
||||||
// 注册
|
// 注册
|
||||||
register: (userData) => api.post('/auth/register', userData),
|
register: (userData) => api.post('/api/auth/register', userData),
|
||||||
|
|
||||||
// 登出
|
// 登出
|
||||||
logout: () => api.post('/auth/logout'),
|
logout: () => api.post('/api/auth/logout'),
|
||||||
|
|
||||||
// 检查登录状态
|
// 检查登录状态
|
||||||
checkLogin: () => api.get('/auth/check'),
|
checkLogin: () => api.get('/api/auth/check'),
|
||||||
};
|
};
|
||||||
|
|
||||||
// 用户相关API
|
// 用户相关API
|
||||||
export const userAPI = {
|
export const userAPI = {
|
||||||
// 获取用户资料
|
// 获取用户资料
|
||||||
getProfile: () => api.get('/user/profile'),
|
getProfile: () => api.get('/api/user/profile'),
|
||||||
|
|
||||||
// 修改密码
|
// 修改密码
|
||||||
changePassword: (passwordData) => api.post('/user/change-password', passwordData),
|
changePassword: (passwordData) => api.post('/api/user/change-password', passwordData),
|
||||||
|
|
||||||
// 获取用户统计
|
// 获取用户统计
|
||||||
getStats: () => api.get('/user/stats'),
|
getStats: () => api.get('/api/user/stats'),
|
||||||
|
|
||||||
// 删除账户
|
// 删除账户
|
||||||
deleteAccount: (password) => api.post('/user/delete', { password }),
|
deleteAccount: (password) => api.post('/api/user/delete', { password }),
|
||||||
};
|
};
|
||||||
|
|
||||||
// 60s API相关接口
|
// 60s API相关接口
|
||||||
export const api60s = {
|
export const api60s = {
|
||||||
// 抖音热搜
|
// 抖音热搜
|
||||||
getDouyinHot: () => api.get('/60s/douyin'),
|
getDouyinHot: () => api.get('/api/60s/douyin'),
|
||||||
|
|
||||||
// 微博热搜
|
// 微博热搜
|
||||||
getWeiboHot: () => api.get('/60s/weibo'),
|
getWeiboHot: () => api.get('/api/60s/weibo'),
|
||||||
|
|
||||||
// 猫眼票房
|
// 猫眼票房
|
||||||
getMaoyanBoxOffice: () => api.get('/60s/maoyan'),
|
getMaoyanBoxOffice: () => api.get('/api/60s/maoyan'),
|
||||||
|
|
||||||
// 60秒读懂世界
|
// 60秒读懂世界
|
||||||
get60sNews: () => api.get('/60s/60s'),
|
get60sNews: () => api.get('/api/60s/60s'),
|
||||||
|
|
||||||
// 必应壁纸
|
// 必应壁纸
|
||||||
getBingWallpaper: () => api.get('/60s/bing-wallpaper'),
|
getBingWallpaper: () => api.get('/api/60s/bing-wallpaper'),
|
||||||
|
|
||||||
// 天气信息
|
// 天气信息
|
||||||
getWeather: (city = '北京') => api.get(`/60s/weather?city=${encodeURIComponent(city)}`),
|
getWeather: (city = '北京') => api.get(`/api/60s/weather?city=${encodeURIComponent(city)}`),
|
||||||
};
|
};
|
||||||
|
|
||||||
// 健康检查
|
// 健康检查
|
||||||
export const healthAPI = {
|
export const healthAPI = {
|
||||||
check: () => api.get('/health'),
|
check: () => api.get('/api/health'),
|
||||||
};
|
};
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
|
|||||||
72
nginx-config-example.conf
Normal file
72
nginx-config-example.conf
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# Nginx配置示例 - InfoGenie部署
|
||||||
|
|
||||||
|
# 前端配置 - infogenie.shumengya.top
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name infogenie.shumengya.top;
|
||||||
|
|
||||||
|
# 重定向HTTP到HTTPS
|
||||||
|
location / {
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name infogenie.shumengya.top;
|
||||||
|
|
||||||
|
# SSL证书配置
|
||||||
|
ssl_certificate /path/to/cert.pem;
|
||||||
|
ssl_certificate_key /path/to/key.pem;
|
||||||
|
|
||||||
|
# 前端静态文件目录
|
||||||
|
root /var/www/infogenie;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# 处理React路由
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 安全相关配置
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN";
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header X-Content-Type-Options "nosniff";
|
||||||
|
}
|
||||||
|
|
||||||
|
# 后端配置 - infogenie.api.shumengya.top
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name infogenie.api.shumengya.top;
|
||||||
|
|
||||||
|
# 重定向HTTP到HTTPS
|
||||||
|
location / {
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name infogenie.api.shumengya.top;
|
||||||
|
|
||||||
|
# SSL证书配置
|
||||||
|
ssl_certificate /path/to/cert.pem;
|
||||||
|
ssl_certificate_key /path/to/key.pem;
|
||||||
|
|
||||||
|
# 反向代理到后端服务
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:5000;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 安全相关配置
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN";
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header X-Content-Type-Options "nosniff";
|
||||||
|
|
||||||
|
# 允许较大的上传文件
|
||||||
|
client_max_body_size 10M;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user