CodeIgniter3如何让控制器同时支持API与Web请求?
当然不用写两套控制器!这在CodeIgniter 3里完全可以通过几种业内常用的方式实现,既优雅又能避免重复代码。我给你梳理几个靠谱的方案:
方案1:通过路由前缀识别API请求,在控制器内切换输出逻辑
首先在application/config/routes.php里配置路由,把所有带api前缀的请求映射到对应的控制器,这样同一套控制器就能处理网页和API两种请求:
// 把/api/控制器名/方法名 映射到 控制器名/方法名 $route['api/(:controller)/(:method)'] = '$1/$2'; // 处理默认方法的情况(比如访问/api/posts 对应Posts控制器的index方法) $route['api/(:controller)'] = '$1';
然后在你的控制器方法里,通过CI的URI类判断当前请求是否来自API前缀,再决定输出方式:
public function index() { // 先统一获取业务数据——不管是网页还是API,核心逻辑完全复用 $data['posts'] = $this->post_model->get_all_posts(); // 判断是否是API请求 if ($this->uri->segment(1) === 'api') { // 输出JSON格式结果 $this->output ->set_content_type('application/json') ->set_output(json_encode($data)); } else { // 加载HTML视图渲染页面 $this->load->view('posts/index', $data); } }
这种方式直观易懂,用户通过URL就能明确访问的是网页还是API,维护成本很低。
方案2:通过请求头判断(更符合RESTful规范)
如果不想依赖URL前缀,也可以通过HTTP请求头来识别请求类型。比如检查Accept头是否为application/json,这样客户端只要在请求时指定这个头,不管URL是什么,都返回JSON:
public function index() { $data['posts'] = $this->post_model->get_all_posts(); // 读取请求头并判断 $accept_header = $this->input->get_request_header('Accept'); if (strpos($accept_header, 'application/json') !== false) { $this->output ->set_content_type('application/json') ->set_output(json_encode($data)); } else { $this->load->view('posts/index', $data); } }
这种方式更灵活,适合需要同一URL支持多种输出格式的场景,也是业内RESTful API的常用实践。
方案3:封装基础控制器,统一处理输出逻辑
为了避免每个控制器方法都重复写判断逻辑,你可以创建一个基础控制器,把输出逻辑封装进去,让所有业务控制器都继承它——这是大型项目里最推荐的做法。
首先在application/core/MY_Controller.php里创建基础控制器:
class MY_Controller extends CI_Controller { protected function send_response($data, $view_path = '') { // 同时支持URL前缀和请求头两种判断方式,兼容性更强 $is_api = ($this->uri->segment(1) === 'api') || (strpos($this->input->get_request_header('Accept'), 'application/json') !== false); if ($is_api) { $this->output ->set_content_type('application/json') ->set_output(json_encode($data)); } else { $this->load->view($view_path, $data); } } }
然后你的业务控制器继承这个基础控制器,直接调用封装好的方法即可:
class Posts extends MY_Controller { public function index() { $data['posts'] = $this->post_model->get_all_posts(); // 传入数据和视图路径,剩下的交给基础控制器处理 $this->send_response($data, 'posts/index'); } }
这种方式最大化复用代码,后续如果要修改输出逻辑,只需要改基础控制器就行,非常方便。
额外提示
- 如果你需要对API请求做额外处理(比如身份验证、参数校验),可以在基础控制器的
__construct方法里添加判断,比如如果是API请求就执行验证逻辑,网页请求则跳过。 - 输出JSON时,可以结合状态码优化响应,比如用
$this->output->set_status_header(404)返回404状态,让API更规范。
内容的提问来源于stack exchange,提问作者Eoghan
相关产品推荐
相关产品推荐

