必须踩准注解位置、路由绑定、生成路径三块砖,漏一则swagger.json为空或404;注解须紧贴public方法无空行,path须与真实URL完全一致(含前缀/),嵌套参数需扁平化,生成命令路径及权限须正确,且需透传路由避免404。

能偷懒,但得先踩准三块砖:注解位置、路由绑定、生成路径——漏一块,swagger.json 就是空的或 404。
注解必须紧贴 public 方法,且不能靠函数签名“猜”参数
Swagger-PHP 不运行代码,只扫描 PHPDoc 块。它不认识 public function index($id = 1) 里的 $id,也不会把 @param 当成 OpenAPI 参数。
-
@OAGet、@OAPost必须写在控制器里public方法正上方,中间不能有空行 - 查询参数必须显式声明:
@OAParameter(name="page", in="query", schema=@OASchema(type="integer")) - JSON Body 提交不能只写
@OAProperty,得套完整结构:@OARequestBody(@OAJsonContent(@OAProperty(property="name", type="string"))) - 嵌套字段如
{"user": {"profile": {"age": 25}}},得扁平化拆成user_profile_age,否则不进文档
path 值不是路由定义片段,而是真实可访问的完整 URL
你浏览器里输入的地址,就是 path 的唯一标准。ThinkPHP 的 Route::group(['prefix' => 'api/v1']) 不会自动拼接进注解,全靠你手写。
- 如果路由是
Route::get('api/v1/users', 'UserController@index'),注解必须是path="/api/v1/users"(开头带/,含全部前缀) - 写成
path="/users"或path="api/v1/users",Swagger UI 会发错请求,后端返回 404 - 部署在子域名或网关后(如
https://api.example.com),还得在@OAInfo里补servers:@OAServer(url="https://api.example.com")
生成命令扫不到接口?先查路径、权限、autoload
vendor/bin/openapi 扫出来 paths: {},90% 是路径没对上,不是工具坏了。
立即学习“PHP免费学习笔记(深入)”;
- ThinkPHP 8 默认控制器在
app/controller/,但如果你用了多应用,比如app/api/controller/,就得明确指定:php vendor/bin/openapi app/api/controller/ -o public/swagger.json - 确保这些控制器文件被 Composer 加载:检查
composer.json的autoload.psr-4是否包含对应命名空间(如"app\api\": "app/api/") - Linux/macOS 下注意文件权限——如果
app/controller/UserController.php属主不是当前执行用户,openapi会静默跳过 - Windows WSL 或某些 Docker 环境下,
vendor/bin/openapi可能没执行权限,手动加:chmod +x vendor/bin/openapi
swagger.json 访问 404?别信“放 public 下就完事”
ThinkPHP 默认路由会拦截所有未匹配路径,public/swagger.json 是静态文件,但直接访问 /swagger.json 会被当成未定义路由,返回 HTML 或 404。
- 必须加透传路由:在
app/route/app.php里加一行:Route::get('swagger.json', function () { return file_get_contents(public_path() . '/swagger.json'); }); - 确认 Web 服务器允许直接读取
.json文件(Nginx/Apache 别用location ~ .php$规则误拦) - Swagger UI 页面里配置的 URL 必须是绝对路径,比如
http://localhost/swagger.json,不能是相对路径./swagger.json
最麻烦的其实是 @OAServer 和 in="body" 这类细节:漏掉 @OAServer,UI 能打开但 “Try it out” 必然失败;把 in 写成 url 或 get,参数就直接消失——这些地方没报错,只静默忽略。



















