# Yinli API 基于 Golang Gin 框架构建的高性能 RESTful API 服务,集成了 JWT 认证、Redis 缓存、频率限制、CORS 等安全特性。 ## 🚀 技术架构 ### 核心技术栈 - **Web 框架**: [Gin](https://gin-gonic.com/) - 高性能的 HTTP Web 框架 - **数据库**: [MySQL 8.0](https://dev.mysql.com/doc/) - 关系型数据库 - **缓存**: [Redis](https://redis.io/) - 内存数据库,用于缓存和频率限制 - **ORM**: [GORM](https://gorm.io/) - Go 语言 ORM 库 - **配置管理**: [Viper](https://github.com/spf13/viper) - 配置文件管理 - **认证**: [JWT](https://jwt.io/) - JSON Web Token 认证 - **文档**: [Swagger](https://swagger.io/) - API 文档自动生成 - **测试**: [Testify](https://github.com/stretchr/testify) - 测试框架 - **容器化**: [Docker](https://www.docker.com/) - 容器化部署 ### 安全特性 - **JWT 认证**: 基于 JSON Web Token 的用户认证 - **CORS 支持**: 跨域资源共享配置 - **频率限制**: 基于 Redis 的 API 频率限制 - **密码加密**: 使用 bcrypt 加密用户密码 - **中间件保护**: 多层中间件安全防护 ### 项目结构 ``` yinli-api/ ├── src/ # 源代码目录 │ ├── main.go # 应用程序入口 │ ├── handler/ # HTTP 处理器 │ ├── middleware/ # 中间件 │ ├── model/ # 数据模型 │ ├── repository/ # 数据访问层 │ ├── service/ # 业务逻辑层 │ └── pkg/ # 可复用的包 │ ├── auth/ # 认证相关 │ ├── cache/ # 缓存操作 │ ├── config/ # 配置管理 │ └── database/ # 数据库连接 ├── config/ # 配置文件 │ ├── dev.yaml # 开发环境配置 │ ├── stage.yaml # 预发布环境配置 │ └── prod.yaml # 生产环境配置 ├── docker/ # Docker 相关文件 ├── doc/ # API 文档 ├── sql/ # 数据库脚本 ├── test/ # 测试文件 ├── build/ # 构建输出 ├── Dockerfile # Docker 镜像构建文件 ├── Makefile # 构建脚本 └── README.md # 项目说明 ``` ## 🛠️ 快速开始 ### 环境要求 - Go 1.21+ - MySQL 8.0+ - Redis 6.0+ - Docker & Docker Compose (可选) ### 本地开发 1. **克隆项目** ```bash git clone cd yinli-api ``` 2. **安装依赖** ```bash make deps ``` 3. **配置数据库** ```bash # 创建数据库 mysql -u root -p < sql/init.sql ``` 4. **启动 Redis** ```bash redis-server ``` 5. **启动开发环境** ```bash make dev ``` ### Docker 部署 项目支持三种环境的 Docker Compose 部署:dev(开发)、stage(预发布)、prod(生产)。 #### Docker 镜像配置(中国大陆用户) 如果在中国大陆使用 Docker,建议配置镜像加速器以提高镜像拉取速度。项目使用官方镜像名称(如 `mysql:8.0`、`redis:7-alpine`),通过配置的 Docker 镜像加速器自动加速拉取。 **方法1:配置 Docker 镜像加速器(推荐)** 根据 Docker 运行模式选择配置位置: **标准 Docker(需要 root 权限):** 编辑或创建 `/etc/docker/daemon.json` 文件: ```bash sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": [ "https://docker.m.daocloud.io", "https://dockerproxy.com", "https://docker.nju.edu.cn" ] } EOF sudo systemctl daemon-reload sudo systemctl restart docker ``` **Rootless Docker(无需 root 权限):** 编辑或创建 `~/.config/docker/daemon.json` 文件: ```bash mkdir -p ~/.config/docker cat > ~/.config/docker/daemon.json <<-'EOF' { "registry-mirrors": [ "https://docker.m.daocloud.io", "https://dockerproxy.com", "https://docker.nju.edu.cn" ] } EOF ``` 然后重启 rootless Docker(**重要:配置后必须重启才能生效**): ```bash # 方法1:重启 rootless Docker 服务 systemctl --user restart docker # 方法2:如果使用 dockerd-rootless,需要重启用户服务 pkill -HUP dockerd # 或者重启整个 rootless Docker systemctl --user stop docker.socket systemctl --user start docker.socket ``` 验证配置: ```bash docker info | grep -A 10 "Registry Mirrors" ``` 如果看到配置的镜像源列表,说明配置成功。 **方法2:使用环境变量(临时)** ```bash # 设置 Docker 镜像代理 export DOCKER_REGISTRY_MIRROR=https://registry.cn-hangzhou.aliyuncs.com ``` **常用国内镜像源(按推荐顺序):** - DaoCloud:`https://docker.m.daocloud.io` ⭐ 推荐 - Docker 代理:`https://dockerproxy.com` - 南京大学:`https://docker.nju.edu.cn` - 上海交大:`https://docker.mirrors.sjtug.sjtu.edu.cn` - 阿里云:`https://registry.cn-hangzhou.aliyuncs.com`(需要登录) - 中科大:`https://docker.mirrors.ustc.edu.cn`(可能不稳定) - 网易:`https://hub-mirror.c.163.com`(可能不稳定) **重要提示:** - 项目使用官方镜像名称(如 `mysql:8.0`、`redis:7-alpine`),通过配置的 Docker 镜像加速器自动加速 - 如果镜像加速器配置正确,Docker 会自动从配置的镜像源拉取镜像 - 如果遇到镜像拉取失败,请确保已重启 Docker 服务使配置生效:`sudo systemctl restart docker` - **Go 模块下载**:Dockerfile 中已配置使用国内 Go 代理(`GOPROXY=https://goproxy.cn,direct`),无需额外配置 #### 开发环境部署 1. **生成 Docker Compose 文件(可选,文件已存在)** ```bash make docker-compose-dev ``` 2. **启动开发环境服务** ```bash make docker-up-dev ``` 3. **查看日志** ```bash make docker-logs ``` 4. **停止服务** ```bash make docker-down-dev ``` #### 预发布环境部署 1. **启动预发布环境服务** ```bash make docker-up-stage ``` 2. **查看日志** ```bash make docker-logs-stage ``` 3. **停止服务** ```bash make docker-down-stage ``` **注意:** 预发布环境使用不同的端口映射(MySQL: 3307, Redis: 6380),避免与开发环境冲突。 #### 生产环境部署 1. **设置环境变量(重要!)** ```bash export MYSQL_ROOT_PASSWORD=your_secure_password export REDIS_PASSWORD=your_redis_password ``` 2. **启动生产环境服务** ```bash make docker-up-prod ``` 3. **查看日志** ```bash make docker-logs-prod ``` 4. **停止服务** ```bash make docker-down-prod ``` **注意:** - 生产环境使用不同的端口映射(MySQL: 3308, Redis: 6381) - 生产环境配置了健康检查和自动重启策略 - 请务必在生产环境部署前修改配置文件中的敏感信息(JWT密钥、数据库密码等) ## 📋 可用命令 ### 开发命令 ```bash make dev # 启动开发环境 make stage # 启动预发布环境 make prod # 启动生产环境 ``` ### 构建命令 ```bash make build # 构建 Linux 版本 make build-all # 构建所有平台版本 make clean # 清理构建文件 ``` ### 测试命令 ```bash make test # 运行测试 make test-coverage # 运行测试并生成覆盖率报告 make benchmark # 运行基准测试 ``` ### 代码质量 ```bash make fmt # 格式化代码 make vet # 静态检查 make lint # 代码规范检查 make check # 执行所有检查 ``` ### 文档生成 ```bash make docs # 生成 API 文档 make docs-serve # 启动文档服务器 ``` ### Docker 操作 ```bash make docker-build # 构建 Docker 镜像 make docker-compose-dev # 生成开发环境 Docker Compose 文件 make docker-up-dev # 启动开发环境容器 make docker-up-stage # 启动预发布环境容器 make docker-up-prod # 启动生产环境容器 make docker-down # 停止所有容器 make docker-down-dev # 停止开发环境容器 make docker-down-stage # 停止预发布环境容器 make docker-down-prod # 停止生产环境容器 make docker-logs # 查看开发环境容器日志 make docker-logs-stage # 查看预发布环境容器日志 make docker-logs-prod # 查看生产环境容器日志 make docker-ps # 查看所有容器状态 ``` ## 🔧 配置说明 ### 环境配置 项目支持三种环境配置: - `dev` - 开发环境 - `stage` - 预发布环境 - `prod` - 生产环境 配置文件位于 `config/` 目录下,可通过环境变量 `APP_ENV` 或命令行参数 `-env` 指定。 ### 主要配置项 ```yaml server: port: 1234 # 服务端口 mode: debug # 运行模式 (debug/release) database: host: localhost # 数据库地址 port: 3306 # 数据库端口 username: root # 数据库用户名 password: sasasasa # 数据库密码 dbname: yinli # 数据库名称 redis: host: localhost # Redis 地址 port: 6379 # Redis 端口 password: "" # Redis 密码 db: 0 # Redis 数据库 jwt: secret: your-secret-key # JWT 密钥 expireHours: 24 # 令牌过期时间(小时) rateLimit: enabled: true # 是否启用频率限制 requests: 100 # 每个时间窗口的请求数 window: 60 # 时间窗口(秒) ``` ## 📡 API 接口 ### 认证接口 | 方法 | 路径 | 描述 | 认证 | |------|------|------|------| | POST | `/api/auth/register` | 用户注册 | ❌ | | POST | `/api/auth/login` | 用户登录 | ❌ | ### 用户接口 | 方法 | 路径 | 描述 | 认证 | |------|------|------|------| | GET | `/api/user/profile` | 获取用户资料 | ✅ | | PUT | `/api/user/profile` | 更新用户资料 | ✅ | | PUT | `/api/user/password` | 修改密码 | ✅ | ### 管理员接口 | 方法 | 路径 | 描述 | 认证 | |------|------|------|------| | GET | `/api/admin/users` | 获取用户列表 | ✅ (管理员) | | DELETE | `/api/admin/users/{id}` | 删除用户 | ✅ (管理员) | | PUT | `/api/admin/users/{id}/status` | 更新用户状态 | ✅ (管理员) | ### 系统接口 | 方法 | 路径 | 描述 | 认证 | |------|------|------|------| | GET | `/health` | 健康检查 | ❌ | | GET | `/swagger/*` | API 文档 | ❌ | ## 🧪 接口测试 ### 使用 curl 测试 1. **用户注册** ```bash curl -X POST http://localhost:1234/api/auth/register \ -H "Content-Type: application/json" \ -d '{ "name": "testuser", "password": "password123" }' ``` 2. **用户登录** ```bash curl -X POST http://localhost:1234/api/auth/login \ -H "Content-Type: application/json" \ -d '{ "name": "testuser", "password": "password123" }' ``` 3. **获取用户资料** ```bash curl -X GET http://localhost:1234/api/user/profile \ -H "Authorization: Bearer YOUR_JWT_TOKEN" ``` ### 使用 Postman 1. 导入 Postman 集合文件(如果有) 2. 设置环境变量 `base_url` 为 `http://localhost:1234` 3. 在认证接口获取 JWT token 4. 在需要认证的接口中添加 `Authorization: Bearer {token}` 头 ## 🔍 开发调试 ### 日志查看 ```bash # 查看应用日志 tail -f logs/app.log # 查看 Docker 容器日志 make docker-logs ``` ### 数据库调试 ```bash # 连接数据库 mysql -h localhost -u root -p yinli # 查看用户表 SELECT * FROM user; ``` ### Redis 调试 ```bash # 连接 Redis redis-cli # 查看所有键 KEYS * # 查看频率限制 KEYS rate_limit:* ``` ### 性能监控 ```bash # 查看应用性能 go tool pprof http://localhost:1234/debug/pprof/profile # 内存使用情况 go tool pprof http://localhost:1234/debug/pprof/heap ``` ### 端口进程管理 在 Ubuntu 环境中,如果端口被占用,可以使用以下命令查找并终止进程: ```bash # 方法1: 使用 netstat 查找端口对应的进程 netstat -tuln | grep :1234 # 方法2: 使用 lsof 查找端口对应的进程(需要安装: sudo apt install lsof) lsof -i :1234 # 方法3: 使用 ss 查找端口对应的进程 ss -tulnp | grep :1234 # 获取进程 ID (PID) 后,使用以下命令终止进程 kill # 如果进程无法正常终止,可以使用强制终止 kill -9 # 或者使用一行命令直接终止占用端口的进程 kill $(lsof -t -i:1234) # 如果 lsof 不可用,可以使用 fuser(需要安装: sudo apt install psmisc) sudo fuser -k 1234/tcp ``` **示例:** ```bash # 1. 查找端口 1234 对应的进程 $ netstat -tulnp | grep :1234 tcp6 0 0 :::1234 :::* LISTEN 449736/main # 2. 或者使用 lsof 获取更详细信息 $ lsof -i :1234 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME main 449736 table 9u IPv6 903989 0t0 TCP *:1234 (LISTEN) # 3. 终止进程(PID 为 449736) $ kill 449736 # 4. 如果进程无法正常终止,使用强制终止 $ kill -9 449736 ``` ## 📊 测试报告 运行测试并生成报告: ```bash make test-coverage ``` 测试报告将生成在 `build/coverage.html`,可在浏览器中查看详细的覆盖率信息。 ## 🚀 部署指南 ### 生产环境部署 1. **构建生产版本** ```bash make build ``` 2. **配置生产环境** ```bash # 修改 config/prod.yaml # 设置正确的数据库和 Redis 连接信息 # 更改 JWT 密钥 ``` 3. **使用 Docker 部署** ```bash # 设置环境变量 export MYSQL_ROOT_PASSWORD=your_secure_password export REDIS_PASSWORD=your_redis_password # 启动生产环境 make docker-up-prod # 查看日志 make docker-logs-prod ``` ### 环境变量 生产环境建议使用环境变量覆盖敏感配置: ```bash export YINLI_DATABASE_PASSWORD=your_db_password export YINLI_JWT_SECRET=your_jwt_secret export YINLI_REDIS_PASSWORD=your_redis_password ``` ## 📚 主要依赖库 ### 核心依赖 - [Gin Web Framework](https://github.com/gin-gonic/gin) - HTTP Web 框架 - [GORM](https://github.com/go-gorm/gorm) - ORM 库 - [Viper](https://github.com/spf13/viper) - 配置管理 - [JWT-Go](https://github.com/golang-jwt/jwt) - JWT 实现 - [Go-Redis](https://github.com/go-redis/redis) - Redis 客户端 ### 中间件 - [Gin-CORS](https://github.com/gin-contrib/cors) - CORS 中间件 - [Gin-Swagger](https://github.com/swaggo/gin-swagger) - Swagger 文档 ### 测试工具 - [Testify](https://github.com/stretchr/testify) - 测试断言库 - [HTTP Test](https://golang.org/pkg/net/http/httptest/) - HTTP 测试工具 ### 开发工具 - [Air](https://github.com/cosmtrek/air) - 热重载工具 - [GolangCI-Lint](https://github.com/golangci/golangci-lint) - 代码检查工具 ## 🤝 贡献指南 1. Fork 项目 2. 创建特性分支 (`git checkout -b feature/AmazingFeature`) 3. 提交更改 (`git commit -m 'Add some AmazingFeature'`) 4. 推送到分支 (`git push origin feature/AmazingFeature`) 5. 开启 Pull Request ## 📄 许可证 本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情。 ## 🆘 常见问题 ### Q: 如何修改数据库连接? A: 修改 `config/{env}.yaml` 文件中的 `database` 配置项。 ### Q: 如何添加新的 API 接口? A: 1. 在 `src/handler` 中添加处理函数 2. 在 `src/handler/router.go` 中注册路由 3. 添加相应的测试用例 ### Q: 如何自定义中间件? A: 在 `src/middleware` 目录下创建新的中间件文件,参考现有中间件的实现。 ### Q: 如何部署到生产环境? A: 1. 设置环境变量: ```bash export MYSQL_ROOT_PASSWORD=your_secure_password export REDIS_PASSWORD=your_redis_password ``` 2. 修改 `config/prod.yaml` 中的敏感配置(JWT密钥等) 3. 启动生产环境: ```bash make docker-up-prod ``` 4. 查看日志: ```bash make docker-logs-prod ``` ### Q: Docker Compose 支持哪些环境? A: 项目支持三种环境的 Docker Compose 部署: - **dev**: 开发环境,端口映射 MySQL:3306, Redis:6379 - **stage**: 预发布环境,端口映射 MySQL:3307, Redis:6380 - **prod**: 生产环境,端口映射 MySQL:3308, Redis:6381,包含健康检查和自动重启 ### Q: Docker 镜像拉取失败怎么办? A: 如果在中国大陆遇到镜像拉取超时或失败,可以: 1. **配置 Docker 镜像加速器**(推荐): ```bash sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": [ "https://docker.m.daocloud.io", "https://dockerproxy.com", "https://docker.nju.edu.cn" ] } EOF sudo systemctl daemon-reload sudo systemctl restart docker ``` **重要:配置后必须重启 Docker 服务才能生效!** 验证配置: ```bash docker info | grep -A 10 "Registry Mirrors" ``` 如果看到镜像源列表,说明配置成功。 2. **Rootless Docker 配置**: - 如果使用 rootless Docker(`docker version` 显示 `Context: rootless`),配置文件位置为 `~/.config/docker/daemon.json` - 配置后重启:`systemctl --user restart docker` - 验证:`docker info | grep -A 10 "Registry Mirrors"` 3. **使用官方镜像名称**:项目使用官方镜像名称(如 `mysql:8.0`、`redis:7-alpine`),通过配置的 Docker 镜像加速器自动加速拉取 4. **Go 模块下载失败**: - Dockerfile 中已配置使用国内 Go 代理(`GOPROXY=https://goproxy.cn,direct`) - 如果仍然失败,可以在 Dockerfile 中修改 GOPROXY 环境变量: ```dockerfile ENV GOPROXY=https://goproxy.cn,https://goproxy.io,direct ``` - 常用 Go 代理:`https://goproxy.cn`、`https://goproxy.io`、`https://mirrors.aliyun.com/goproxy/` 5. **检查网络连接**:确保能够访问镜像仓库 - 测试镜像源:`curl -I https://docker.m.daocloud.io/v2/` - 如果镜像加速器配置已生效但仍失败,可能是网络问题,可以稍后重试 6. **如果镜像加速器仍未生效**: - 检查配置文件格式是否正确(JSON 格式) - 标准 Docker:检查 `/etc/docker/daemon.json` - Rootless Docker:检查 `~/.config/docker/daemon.json` - 确认已重启 Docker 服务 - 检查 Docker 服务状态:`sudo systemctl status docker` 或 `systemctl --user status docker` ### Q: Docker 权限错误(permission denied)怎么办? A: 如果遇到 `Error response from daemon: cannot stop container: permission denied` 错误,可能的原因和解决方法: 1. **Docker 上下文不匹配**(常见原因): 如果系统同时安装了标准 Docker 和 rootless Docker,容器可能由不同的上下文创建。 ```bash # 查看当前 Docker 上下文 docker context show # 查看所有可用的上下文 docker context ls # 如果容器是由标准 Docker 创建的,切换到 default 上下文 docker context use default # 然后尝试停止容器 docker stop docker-mysql-1 # 如果需要切换回 rootless docker context use rootless ``` **提示**:如果容器是通过 `sudo docker compose` 创建的,通常需要使用 `default` 上下文;如果通过普通用户创建的,可能使用 `rootless` 上下文。 2. **临时解决方案(使用 sudo)**: ```bash # 停止并删除容器 sudo docker stop docker-mysql-1 sudo docker rm docker-mysql-1 # 或使用 docker compose sudo docker compose -f docker/docker-compose.stage.yml down ``` 3. **永久解决方案(推荐)**:将用户添加到 `docker` 组 ```bash # 将当前用户添加到 docker 组 sudo usermod -aG docker $USER # 重新登录或执行以下命令使组权限生效 newgrp docker # 验证是否成功 groups | grep docker ``` **注意**:添加到 docker 组后,需要: - 重新登录系统,或 - 执行 `newgrp docker` 命令,或 - 重新打开终端 之后就可以不使用 `sudo` 直接操作 Docker 了。 4. **检查 Docker socket 权限**: ```bash ls -la /var/run/docker.sock ``` 应该显示类似:`srw-rw---- 1 root docker`,表示 `docker` 组有读写权限。 5. **如果使用 rootless Docker**: - Rootless Docker 不需要 sudo,但需要确保 Docker 服务正在运行 - 检查服务状态:`systemctl --user status docker` - 启动服务:`systemctl --user start docker` - 注意:rootless Docker 和标准 Docker 创建的容器是隔离的,不能互相管理 - **如果遇到权限错误,可以尝试**: ```bash # 方法1:重启 rootless Docker 服务(推荐) systemctl --user restart docker # 等待几秒后,再尝试停止容器 docker stop docker-mysql-1 # 方法2:使用 docker kill 强制停止 docker kill docker-mysql-1 docker rm docker-mysql-1 # 方法3:检查并修复 rootless Docker socket 权限 ls -la /run/user/$(id -u)/docker.sock # 应该显示类似:srw-rw---T 1 table ... ```