初始化

This commit is contained in:
2026-03-05 21:27:11 +08:00
commit 130de0fd5d
140 changed files with 21972 additions and 0 deletions

View File

@@ -0,0 +1,304 @@
# Backend Debug Runbook
## 常见问题排查
### 1. 登录返回 401 "账号或密码错误"
#### 症状
```bash
curl -X POST http://127.0.0.1:9501/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "superadmin", "password": "Admin@2026"}'
# 返回: {"code": 401, "message": "账号或密码错误"}
```
#### 排查步骤
1. **检查数据库是否有用户**
```bash
docker exec hyperf-mysql mysql -uroot -p123456 case_db \
-e "SELECT id, username, phone FROM auth_users WHERE deleted_at IS NULL;"
```
2. **如果用户不存在,运行 Seeder**
```bash
docker exec hyperf-skeleton php bin/hyperf.php db:seed --class=DatabaseSeeder
```
3. **验证密码比对逻辑**
```bash
# 检查 User Model 是否使用 password_hash 和 password_verify
# 确保 Seeder 中的密码也是用 password_hash 加密的
```
### 2. 返回 500 "Internal Server Error" - env() 未定义
#### 症状
```bash
curl -X POST http://127.0.0.1:9501/api/auth/sms/send \
-H "Content-Type: application/json" \
-d '{"phone": "18970867739", "purpose": "login"}'
# 返回: {"code": 500, "message": "Internal Server Error"}
```
#### 日志错误
```
[ERROR] Call to undefined function env()[43] in /opt/www/modules/Auth/src/Service/SmsService.php
[ERROR] #0 /opt/www/runtime/container/proxy/Modules_Auth_Http_Controller_Api_SmsController.proxy.php(42):
Modules\Auth\Service\SmsService->send()
```
#### 根因
PHP CLI 和 Swoole Worker 环境中**不提供全局 `env()` 函数**(这是 Laravel 特有的),会导致 `Call to undefined function env()` 错误。
#### 解决方案
**修改前(错误)**
```php
// ❌ 在 Service/Middleware 中直接使用 env()
if (env('APP_ENV', 'development') !== 'production') {
// ...
}
$secret = env('JWT_SECRET', 'default');
```
**修改后(正确)**
```php
// ✅ 使用 Hyperf 的 config() 函数读取配置
$appEnv = \Hyperf\Config\config('app.env', 'development');
if ($appEnv !== 'production') {
// ...
}
$secret = \Hyperf\Config\config('jwt.secret', 'default-secret');
```
**配置文件正确写法**(在配置文件中可以使用 env()
```php
// config/autoload/jwt.php
use function Hyperf\Support\env;
return [
'secret' => env('JWT_SECRET', 'dev-fallback-secret'),
'ttl' => (int) env('JWT_TTL', 7200),
];
```
**常见错误场景**
```php
// ❌ Service 层中使用 env()
class SmsService {
public function send() {
if (env('APP_ENV') !== 'production') { // 报错
// ...
}
}
}
// ❌ Middleware 层中使用 env()
class JwtAuthMiddleware {
public function process() {
$secret = env('JWT_SECRET'); // 报错
}
}
// ❌ 即使添加命名空间前缀也不行
if (\env('APP_ENV') !== 'production') { // 仍然报错
```
**正确实践**
```php
// ✅ Service 层使用 config()
use Hyperf\Config\config;
class SmsService {
public function send() {
$appEnv = config('app.env', 'development');
if ($appEnv !== 'production') {
// ...
}
}
}
// ✅ 配置文件中使用 env()(正确位置)
// config/autoload/app.php
use function Hyperf\Support\env;
return [
'env' => env('APP_ENV', 'development'),
'debug' => env('APP_DEBUG', false),
];
```
### 3. Token 验证失败 - Secret 不一致
#### 症状
```bash
# 登录成功
TOKEN=$(curl -s -X POST http://127.0.0.1:9501/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "superadmin", "password": "Admin@2026"}' | jq -r '.data.access_token')
# 但 profile 接口返回 40102
curl -X GET "http://127.0.0.1:9501/api/auth/profile" \
-H "Authorization: Bearer $TOKEN"
# 返回: {"code": 40102, "message": "Token invalid"}
```
#### 根因
AuthService 和 JwtAuthMiddleware 使用不同的 JWT secret。
#### 解决方案
**确保两处使用相同的 secret**
```php
// AuthService.php
protected function generateToken(User $user, string $type = 'access', ?int $ttlOverride = null): string
{
$secret = 'dev-only-insecure-secret-20260304'; // 固定值,不要用 md5(__DIR__)
// ...
}
// JwtAuthMiddleware.php
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
// ...
$secret = 'dev-only-insecure-secret-20260304'; // 与 AuthService 完全相同
$decoded = JWT::decode($token, new Key($secret, 'HS256'));
// ...
}
```
**禁止的做法**
```php
// ❌ 使用 md5(__DIR__) 会导致路径不一致
$secret = 'dev-only-insecure-key-' . md5(__DIR__);
```
### 4. 服务启动失败 - 异步队列配置缺失
#### 症状
```bash
docker compose restart hyperf-skeleton
docker logs hyperf-skeleton --tail 50
```
#### 日志错误
```
[ERROR] Entry "Modules\Security\Listener\SecurityEventListener" cannot be resolved:
Entry "Hyperf\AsyncQueue\Driver\DriverFactory" cannot be resolved
```
```
[ERROR] [Error] default is a invalid driver
```
#### 根因
使用了异步队列,但缺少 `config/autoload/async_queue.php` 配置。
#### 解决方案
创建配置文件:
```php
<?php
declare(strict_types=1);
use function Hyperf\Support\env;
return [
'default' => [
'driver' => env('ASYNC_QUEUE_DRIVER', 'redis'),
'channel' => 'queue',
'retry_after' => 60,
'block_seconds' => 5,
'max_messages' => 100,
'redis' => [
'pool' => 'default',
],
],
];
```
### 5. 服务启动失败 - Config 对象未注入
#### 症状
```
[ERROR] Entry "Hyperf\Config\Config" cannot be resolved:
Parameter $configs of __construct() has no value defined or guessable
```
#### 根因
Hyperf Config 对象未在 dependencies.php 中注册。
#### 解决方案
**检查 `config/autoload/dependencies.php`**
```php
return [
Hyperf\Database\Migrations\Migrator::class => App\Database\MigratorFactory::class,
Hyperf\Database\Seeders\Seed::class => App\Database\SeedFactory::class,
// 确保 Config 不在这里注册Hyperf 会自动注册)
];
```
## 验证清单
### 新模块开发前
- [ ] 检查是否需要队列配置
- [ ] 检查是否需要缓存配置
- [ ] 检查是否需要 JWT 配置
- [ ] 所有 `env()` 都有默认值
### 代码修改后
- [ ] 不在 Service/Middleware 中使用 `config()`
- [ ] JWT secret 使用固定值或环境变量
- [ ] AuthService 和 JwtAuthMiddleware 使用相同 secret
- [ ] 重启服务并测试关键路径
### 部署前
- [ ] 生产环境设置 `JWT_SECRET` 环境变量
- [ ] 检查 .env.example 是否包含所有必要的环境变量
- [ ] 运行 Seeder 确保初始数据正确
## 调试命令
### 查看日志
```bash
# Hyperf 应用日志
docker logs hyperf-skeleton --tail 100 -f
# 数据库日志
docker logs hyperf-mysql --tail 50
# Redis 日志
docker logs hyperf-redis --tail 50
```
### 进入容器调试
```bash
docker exec -it hyperf-skeleton bash
# 运行迁移
php bin/hyperf.php migrate
# 运行 Seeder
php bin/hyperf.php db:seed
# 检查 PHP 语法
php -l modules/Auth/src/Service/AuthService.php
```
### 测试 API
```bash
# 登录
curl -X POST http://127.0.0.1:9501/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "superadmin", "password": "Admin@2026"}'
# 使用 token 访问受保护接口
TOKEN="your-access-token-here"
curl -X GET "http://127.0.0.1:9501/api/auth/profile" \
-H "Authorization: Bearer $TOKEN"