Swagger在CodeIgniter中需手动集成注释扫描、JSON输出、UI渲染三步;必须用zircote/swagger-php^4.9支持PHP8+,注释以@OA\前缀、换行闭合,路径须为绝对目录,JSON响应头需设Content-Type: application/json,UI中url须为可访问的绝对API地址。

Swagger 在 CodeIgniter 中不是开箱即用的,必须手动集成注释扫描 + JSON 输出 + UI 渲染三步。直接装个包、加几行配置就想出文档,基本会卡在 openapi->toJson() 报空或路径找不到。
注释必须用 @OA\ 前缀,且依赖 zircote/swagger-php 4.x
CodeIgniter 3/4 都不自带 OpenAPI 解析器,swagger-php 是唯一能从 PHPDoc 提取结构化数据的主流工具。低版本(如 2.x)不支持 PHP 8+ 的属性语法,而 CI4 多数项目已升到 PHP 8.1+,所以必须用 composer require zircote/swagger-php:^4.9。注释写法示例:
/**
* @OA\Info(title="User API", version="1.0.0")
*/
class Users extends RestController
{
/**
* @OA\Get(
* path="/api/users",
* summary="获取用户列表",
* @OA\Response(response="200", description="OK")
* )
*/
public function index_get()
{
// ...
}
}
注意:@OA\ 不是 @SWG\(旧版 Swagger 2.0),也不支持 /** @OA\Info */ 这种单行写法——必须换行、必须完整闭合、类和方法注释都得有顶层 @OA\Info 或 @OA\OpenApi。
scan() 路径必须指向真实控制器文件,不能用 APPPATH 动态拼接
常见错误是写 \OpenApi\scan(APPPATH . 'controllers'),但 APPPATH 在 CI3 是 application/,在 CI4 是 app/,而 scan() 实际需要的是含 .php 后缀的绝对路径目录(比如 /var/www/myapp/app/Controllers)。更稳妥做法是硬编码或通过环境变量传入:
- CI3:用
__DIR__ . '/../controllers'(假设 Swagger 控制器放在application/controllers同级) - CI4:用
APPPATH . 'Controllers',但要确认目录名是大写的Controllers(非controllers) - 扫描后若返回空对象,用
var_dump(glob($path . '/*.php'))先验证路径下是否真有可读的 PHP 文件
JSON 输出必须设对 Content-Type,否则 Swagger UI 加载失败
生成的 JSON 接口(如 /api/docs)如果没加 header('Content-Type: application/json'),Swagger UI 会静默报 TypeError: Failed to fetch。这不是跨域问题,是响应头类型不匹配。同时注意:
- 不要用
echo json_encode(...)手动输出——$openapi->toJson()已含格式化和转义 - 避免在输出前有任何
echo、print或空白字符,否则 JSON 会以 HTML 开头导致解析失败 - CI4 的
ResourceController默认会加Content-Type: application/json,但普通CI_Controller不会,必须显式设置
Swagger UI 页面里的 url 必须是可公开访问的绝对路径
UI 页面(比如 views/swagger.php)中初始化 Swagger UI 的 JS 代码里,url 字段填的是后端 JSON 接口地址,不是本地文件路径:
const ui = SwaggerUIBundle({
url: "https://api.example.com/api/docs",
dom_id: '#swagger-ui',
})
这个地址必须满足两个条件:
- 能被浏览器直接访问并返回合法 JSON(状态码 200,Content-Type 正确)
- 与 UI 页面同域,或后端已配好 CORS(
Access-Control-Allow-Origin: *)
很多人把 url 写成 /asset/swagger.json 或 ./swagger.json,结果 UI 显示 “Failed to load spec”,其实是请求被浏览器拦截或 404。最省事的调试方式:在浏览器新开标签页,直接访问那个 URL,看能不能看到一屏 JSON。
真正容易被忽略的是注释和代码的耦合深度——@OA\ 注释不是装饰器,它不参与运行时逻辑,但一旦控制器方法签名变更(比如参数名改了、新增了 public function show_get($id = null)),对应注释里的 @OA\Parameter 就必须同步更新,否则文档和实际接口就脱节了。没人会自动校验这个,只能靠开发流程卡点。











