--- name: "ulthon-page-api-dual-mode" description: "指导控制器实现“页面/接口同体”。需要同一路由同时返回 HTML 与 JSON 时调用。" --- # 页面 / 接口同体(Controller Dual Mode) ## 何时调用 - 希望同一个控制器方法既能渲染页面(HTML),也能作为接口返回 JSON。 - 需要让现有页面接口在移动端/脚本调用时返回结构化数据。 ## 触发与认证 - 触发:请求头 `Accept` 包含 `application/json`(框架使用 `request()->isJson()` 判断)。 - 认证:Header 传 `Authorization: Bearer `。 ## 实现要点 - 控制器方法必须调用 `$this->fetch()`,不要使用 `View::fetch()`。 - 无论使用 `$this->assign()` 还是 `View::assign()`,其数据都会被转换为 JSON 返回。 - 若不希望某个 assign 字段出现在 JSON 中,可使用: ```php $this->assign('name', 'value', -1); ``` ## 特殊行为 - 这里存在两种“JSON 语义”,不要混淆: - **接口模式(API)**:只需要 `Accept: application/json`。典型用法是 `index` 的表格分页数据、以及所有 `POST` 提交的 success/error JSON 返回。 - **页面数据模式(Page Data)**:用于“拿页面 assign 的数据”(例如表单的下拉选项、默认值等),需要在 `Accept: application/json` 的基础上追加 `get_page_data=1`。 - `get_page_data=1` 会强制让 `request()->isAjax()` 返回 false,从而避免 `index` 这类方法走“Ajax 分页数据分支”,转而执行 `$this->fetch()`;随后 `$this->fetch()` 会把 `View::fetchData()`(即 assign 的变量)打包成 `json_message()` 返回。 - 当 URL 带 `get_page_data=1` 但请求头不含 `Accept: application/json` 时,框架会直接返回 JSON 错误提示,避免“看起来参数写了但返回了 HTML”的误解。 - 仅在控制器模式(Controller Mode)生效;路由模式(Route Mode)不生效。 ## 常见例子 - 获取列表分页数据(API):只加 `Accept: application/json`,不要带 `get_page_data` - `GET /admin/system.admin/index` - 获取页面 assign 数据(Page Data):`Accept: application/json` + `get_page_data=1` - `GET /admin/system.menu/add?get_page_data=1` - `GET /admin/system.admin/add?get_page_data=1` ## 命令行联调建议 - `php think tools:http:call --app=admin --controller=system.admin --action=index`:默认按 API 语义调用(不再自动追加 `get_page_data=1`) - `php think tools:http:call --app=admin --controller=system.admin --action=add --page-data`:获取该页面的 assign 数据(等价于追加 `get_page_data=1`)