codeigniter 3.1.13 在 nginx 下不能直接用 try_files $uri $uri/ /index.php?$query_string,因其依赖 path_info 而非 query_string 解析路由;正确方式是通过 rewrite + fastcgi_split_path_info 透传 path_info。

CodeIgniter 3.1.13 在 Nginx 下不能直接套用 try_files 做兜底路由,因为 CI3 默认依赖 PATH_INFO(如 /index.php/news/view/123),而 try_files $uri $uri/ /index.php?$query_string 会把请求转成 /index.php?/news/view/123 —— 这种 query string 形式 CI3 不认,$_SERVER['PATH_INFO'] 为空,路由就崩了。
为什么 try_files 直接写 /index.php?$query_string 会失败
CI3.1.13 的 URL 解析逻辑硬依赖 PATH_INFO 或 QUERY_STRING 中的 s=xxx(需开启 $config['enable_query_strings'] = TRUE)。但标准 try_files 转发不带 s= 参数,也不触发 PATH_INFO 拆分。结果就是:404 或首页硬跳回 /index.php。
-
try_files $uri $uri/ /index.php?$query_string→ 实际传给 PHP 的是QUERY_STRING=/news/view/123,CI3 不解析 - CI3 默认只从
REQUEST_URI或PATH_INFO提取路由段,不是从原始 query string - 除非你改框架源码或强制启用 query string 模式,否则这条路走不通
正确做法:用 rewrite + fastcgi_split_path_info 配合 PATH_INFO
必须让 Nginx 把路径拆成 SCRIPT_FILENAME 和 PATH_INFO,再透传给 PHP-FPM。这是 CI3 官方文档唯一明确支持的方式。
- 确保 PHP-FPM 配置中
fastcgi_split_path_info已启用(LNMP 环境默认开,宝塔也默认开) -
location块里不能只写try_files,得用rewrite显式构造 PATH_INFO - 推荐放在
server块内、location ~ \.php$之前
location / {
# 先排除真实存在的文件和目录(CSS/JS/图片等)
try_files $uri $uri/ @ci;
}
location @ci {
rewrite ^(.*)$ /index.php?$1 last;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/tmp/php-cgi.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# 关键:让 Nginx 拆出 PATH_INFO
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
如果坚持只用 try_files,唯一可行变通方案
只能退回到 CI3 的 query string 模式,即把所有路由塞进 s= 参数,并在 application/config/config.php 里显式开启:
- 设置
$config['enable_query_strings'] = TRUE; - 设置
$config['controller_trigger'] = 'c';,$config['function_trigger'] = 'm';(可选) - 然后 Nginx 用这个
try_files:
location / {
try_files $uri $uri/ /index.php?s=$uri&$args;
}
注意:s=$uri 后面必须加 &$args,否则原有 GET 参数(如 ?ref=abc)会丢失;且所有链接必须写成 /index.php?s=/news/view/123 形式,前端生成 URL 得手动拼 s=,体验差。
容易踩的坑和验证点
配完别急着 reload,先确认三件事:
- 检查
fastcgi_param PATH_INFO是否真被传下去:在index.php顶部加var_dump($_SERVER['PATH_INFO'] ?? 'MISSING');,访问/news/view/123应输出/news/view/123 - 确认
index.php文件权限可读,且root指向的是 CI 项目根目录(不是application/或public/) - 别在
location /里写if (!-e $request_filename)—— Nginx 官方禁止,易引发 500 或无限重定向 - 宝塔用户直接选「CodeIgniter」伪静态模板(如有),它内部已按 rewrite + PATH_INFO 方式预置,比手写更稳
PATH_INFO 的传递链很脆弱:Nginx → fastcgi_param → PHP-FPM → $_SERVER,中间任一环断掉,CI3 就收不到路由。调试时优先打点看 $_SERVER 数组,而不是猜配置有没有生效。











