You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:51:19