📦 已从独立仓库
HanphoneJan/hanphone-chat迁移至此(本仓库chat-server/)。 协议与部署见仓库docs/chat/(android-protocol.md为 App 对接”唯一事实来源”)。
高性能的实时聊天应用后端服务,基于 Node.js + Express + Socket.IO + PostgreSQL 构建
| 技术 | 版本 | 说明 |
|---|---|---|
| Node.js | >= 20.5 | JavaScript 运行时 |
| TypeScript | 5.1.6 | 类型安全的 JavaScript 超集 |
| Express | 4.18.2 | Web 应用框架 |
| Socket.IO | 4.7.2 | WebSocket 服务端库 |
| PostgreSQL | 13+ | 关系型数据库 |
| pg | 8.8.0 | PostgreSQL 客户端 |
| jsonwebtoken | 9.0.2 | JWT 生成和验证 |
| bcryptjs | 2.4.3 | 密码加密 |
| cors | 2.8.5 | 跨域资源共享 |
| dotenv | 17.2.3 | 环境变量管理 |
git clone https://github.com/yourusername/hanphone-chat.git
cd hanphone-chat/server
项目使用 pnpm(>= 9)作为包管理器:
pnpm install
确保您已安装 PostgreSQL(推荐版本 13 或更高)。
CREATE DATABASE chat_db;
复制 .env.example 文件为 .env,并更新以下配置:
# 服务器配置
PORT=4010
# 数据库配置(主库 - 聊天数据)
DB_HOST=localhost
DB_PORT=5432
DB_NAME=chat_db
DB_USER=postgres
DB_PASSWORD=your_password
# Blog 服务 API(用户数据同步,不再直连 blog 数据库)
BLOG_API_URL=http://localhost:8080
BLOG_INTERNAL_KEY=your_blog_internal_key
# JWT 配置
JWT_SECRET=your_jwt_secret_key_here
JWT_ISSUER=auth0
# Agent Service 地址
AGENT_SERVICE_URL=http://localhost:8001
# FCM 推送(可选):Firebase 服务账号 JSON 绝对路径;不配置则推送关闭(私信/热点更新)
FCM_SERVICE_ACCOUNT=/path/to/firebase-service-account.json
# 出网代理(国内服务器访问 Google 必须,如 mihomo):留空则直连
FCM_PROXY=http://127.0.0.1:7890
# CORS 配置
ALLOWED_ORIGINS=http://localhost:4010,http://localhost:4011
首次运行前,需要创建数据库表。可以使用以下 SQL 脚本:
-- 用户表
CREATE TABLE t_user (
id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
nickname VARCHAR(50),
email VARCHAR(100),
avatar VARCHAR(255),
type VARCHAR(1) DEFAULT '0',
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_login_time TIMESTAMP,
login_province VARCHAR(50),
login_city VARCHAR(50),
login_lat DECIMAL(10, 6),
login_lng DECIMAL(10, 6),
isOnline BOOLEAN DEFAULT FALSE
);
-- 私信表
CREATE TABLE private_message (
id SERIAL PRIMARY KEY,
sender_id INTEGER NOT NULL,
receiver_id INTEGER NOT NULL,
content TEXT NOT NULL,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
is_read BOOLEAN DEFAULT FALSE,
to_ai BOOLEAN DEFAULT FALSE,
from_ai BOOLEAN DEFAULT FALSE
);
-- 创建索引
CREATE INDEX idx_message_sender ON private_message(sender_id);
CREATE INDEX idx_message_receiver ON private_message(receiver_id);
CREATE INDEX idx_message_timestamp ON private_message(timestamp DESC);
CREATE INDEX idx_user_username ON t_user(username);
CREATE INDEX idx_user_type ON t_user(type);
-- 插入管理员账号(默认密码: admin123)
INSERT INTO t_user (username, password, nickname, type)
VALUES ('admin', '$2a$10$YourHashedPasswordHere', '管理员', '1');
pnpm dev
服务器将在 http://localhost:4010 启动
# 编译 TypeScript
pnpm build
# 运行生产服务器
pnpm start
pnpm clean
server/
├── src/
│ ├── authService.ts # JWT 认证服务
│ ├── (已移除) # AI 人设由 agent-service 管理
│ ├── postgresService.ts # PostgreSQL 数据库服务
│ ├── server.ts # 主服务器入口
│ └── types.ts # TypeScript 类型定义
├── dist/ # 编译输出目录
├── .env # 环境变量配置
├── .env.example # 环境变量示例
├── ecosystem.config.cjs # PM2 进程管理配置
├── package.json # 项目配置
├── tsconfig.json # TypeScript 配置
└── README.md # 项目文档
POST /api/login
Content-Type: application/json
{
"username": "janhizian",
"password": "password"
}
响应:
{
"success": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"username": "janhizian",
"nickname": "寒枫",
"type": "0",
"avatar": "..."
}
}
GET /api/admin/info
Authorization: Bearer <token>
响应:
{
"success": true,
"user": {
"id": 1000,
"username": "admin",
"nickname": "管理员",
"type": "1",
"avatar": "..."
}
}
GET /api/users/all
Authorization: Bearer <token>
GET /api/users
Authorization: Bearer <token>
GET /api/messages/admin
Authorization: Bearer <token>
GET /api/messages/:userId
Authorization: Bearer <token>
| 事件名 | 参数 | 说明 |
|---|---|---|
authenticate |
token: string |
Socket 连接认证 |
userMessage |
message: string, tempId?: string, toAi?: boolean |
用户发送消息 |
adminMessage |
userId: number, message: string, tempId?: string |
管理员发送消息 |
requestUserMessages |
userId: number |
管理员请求用户历史消息 |
disconnect |
- | 断开连接 |
| 事件名 | 参数 | 说明 |
|---|---|---|
message |
message: PrivateMessage |
新消息推送 |
aiStatus |
status: { status, message } |
AI 状态更新 |
notification |
message: string |
通知消息 |
userConnected |
user: User |
用户上线通知 |
userDisconnected |
userId: number |
用户下线通知 |
userListUpdated |
users: User[] |
用户列表更新 |
userMessages |
messages: PrivateMessage[] |
历史消息 |
error |
error: string |
错误消息 |
| 字段 | 类型 | 说明 |
|---|---|---|
| id | SERIAL | 主键 |
| username | VARCHAR(50) | 用户名(唯一) |
| password | VARCHAR(255) | 密码哈希 |
| nickname | VARCHAR(50) | 昵称 |
| VARCHAR(100) | 邮箱 | |
| avatar | VARCHAR(255) | 头像 URL |
| type | VARCHAR(1) | 用户类型(0=普通用户,1=管理员) |
| create_time | TIMESTAMP | 创建时间 |
| update_time | TIMESTAMP | 更新时间 |
| last_login_time | TIMESTAMP | 最后登录时间 |
| login_province | VARCHAR(50) | 登录省份 |
| login_city | VARCHAR(50) | 登录城市 |
| login_lat | DECIMAL(10,6) | 登录纬度 |
| login_lng | DECIMAL(10,6) | 登录经度 |
| isOnline | BOOLEAN | 是否在线 |
| 字段 | 类型 | 说明 |
|---|---|---|
| id | SERIAL | 主键 |
| sender_id | INTEGER | 发送者 ID |
| receiver_id | INTEGER | 接收者 ID |
| content | TEXT | 消息内容 |
| timestamp | TIMESTAMP | 消息时间 |
| is_read | BOOLEAN | 是否已读 |
| to_ai | BOOLEAN | 是否发送给 AI |
| from_ai | BOOLEAN | 是否来自 AI |
JWT 认证服务,提供 Token 生成和验证功能。
主要方法:
generateToken(payload): 生成 JWT TokenverifyToken(token): 验证 JWT TokenhashPassword(password): 密码加密comparePassword(password, hash): 密码验证PostgreSQL 数据库服务,封装所有数据库操作。
主要方法:
createUser(user): 创建用户findUserByUsername(username): 根据用户名查找用户findUserById(id): 根据 ID 查找用户updateUserOnlineStatus(userId, isOnline): 更新用户在线状态saveMessage(message): 保存消息getUserMessages(userId): 获取用户消息getAllUsers(): 获取所有用户getOnlineUsers(): 获取在线用户Server 作为消息中转层,将 AI 相关请求转发给 Agent Service(Python FastAPI)。
AI 回复流程:
toAi: trueaiStatus: 'thinking'/chat/message/stream)aiStreamChunk / aiStreamEnd)aiStatus: 'error'# 1. 安装 PM2 与依赖
npm install -g pm2
pnpm install
# 2. 编译 TypeScript
pnpm build
# 3. 启动服务(自动加载 server/.env,应用名:hanphone-chat-server)
pm2 start ecosystem.config.cjs
# 4. 保存进程列表(开机自启)
pm2 save
# 查看状态
pm2 status
# 查看日志
pm2 logs
# 重启服务
pm2 restart hanphone-chat-server
# 停止 / 删除
pm2 stop hanphone-chat-server
pm2 delete hanphone-chat-server
ecosystem.config.cjs已通过node_args: "--import=dotenv/config"自动加载.env, 启动前请确保已复制server/.env.example为server/.env并填好配置。
仓库已内置 server/Dockerfile(pnpm 构建,多阶段精简):
# 构建镜像
docker build -t hanphone-chat-server .
# 运行(挂载 .env)
docker run -d --name hanphone-server \
-p 4010:4010 \
--env-file .env \
hanphone-chat-server
完整全栈(PostgreSQL + Qdrant + Agent + Server + Client)请使用仓库根目录的
docker compose up -d,见根目录README.md。