codeigniter 3 处理 ajax 请求失败主因是输出未走框架流程、ajax 判断失效或 csrf 令牌未透传;须先 set_content_type() 再 set_output(),弃用 is_ajax_request() 改用 http_accept 或自定义头判断,并从前端 meta 读取 csrf token 透传至 x-csrf-token 头。

CodeIgniter 3 处理 AJAX 请求失败,90% 是因为响应没走框架输出流程、AJAX 判断失效或 CSRF 令牌没透传——不是逻辑写错,而是机制没对齐。
为什么 $this->output->set_content_type() 必须在 set_output() 前调用
CI3 的输出类是延迟写入的,所有 header(包括 Content-Type)必须在最终响应发送前注册。一旦你写 echo json_encode($data); exit;,就绕过了 CI 输出链,Content-Type 仍为 text/html,前端 $.ajax({ dataType: 'json' }) 会直接进 error 回调,且控制台无明显报错。
-
$this->output->set_content_type('application/json', 'utf-8')必须在set_output()之前,显式声明类型和编码,尤其含中文时不能省略'utf-8' -
set_output()只接收字符串,所以得先json_encode($data, JSON_UNESCAPED_UNICODE),再传入 - 禁止任何
header()、echo、print、exit、die—— 它们会让 CI 放弃接管后续输出 - 如需设状态码(如 400),用
$this->output->set_status(400),也必须在set_output()前
为什么别信 $this->input->is_ajax_request()
它只检查 HTTP_X_REQUESTED_WITH === 'XMLHttpRequest',而 Axios、Fetch 默认不发这个头,CDN 或 Nginx 反向代理也可能剥离它。结果就是:明明是 POST JSON 请求,却进了 HTML 渲染分支,返回整页 HTML 被前端当 JSON 解析,直接报 Unexpected token 。
- 更稳的判断方式是看
Accept头:strpos($_SERVER['HTTP_ACCEPT'] ?? '', 'application/json') !== false - 或统一约定自定义头,前端加
X-AJAX: true,后端用$this->input->get_request_header('X-AJAX') === 'true' - 把判断逻辑抽成私有方法(如
_is_ajax_request()),避免散落在各控制器里 - 不要用它做权限控制或关键流程分支——它只是提示,不是安全边界
为什么 AJAX POST 总是 403 或空白响应
CSRF 保护开启时,CI 默认只校验 POST body 中的 csrf_test_name 字段。AJAX 不会自动读取页面中的 meta token 并塞进去,所以请求被静默拦截,返回空响应或 403,且无日志提示。
- 确保模板
里有:<meta name="csrf-token" content="<?php echo $this->security->get_csrf_hash(); ?>"> - 前端用
document.querySelector('meta[name="csrf-token"]').getAttribute('content')读取 token - AJAX 请求头中必须带:
X-CSRF-TOKEN: <token_value></token_value>(注意大小写,CI3 默认识别这个头) - 后端无需手动验证——只要头存在且值匹配 session 中的 hash,CSRF 检查就自动通过
- 不要把 token 放在 data body 里传,CI3 的 CSRF 校验默认不从 body 读这个字段
最容易被忽略的是:URL 路由大小写敏感(Quiz/get_item 必须写成 quiz/get_item),以及 BASE_URL 尾部斜杠缺失导致拼接出错(http://localhost/appquiz/get_item)。这些看似外围的问题,往往比逻辑本身更早拦住请求。











