當CodeIgniter遇到Nginx報404錯誤的解決辦法
由於CodeIgniter當初是設計在apache的,而apache對pathinfo是支援比較好的,所以一切都很nice。但是當你把寫好的程式碼放到nginx上,傻眼了,可能出了CodeIgniter的welcom之外,其他都是404錯誤。而我驚奇的發現,CodeIgniter的官方文件竟然對在Nginx上的配置隻字不提。而你百度”CodeIgniter Nginx 404”又能搜到一堆一堆的文章,奇葩的是幾乎每個文件的配置方法貌似還不大一樣。如果你搞好了還罷,搞不好就是配幾個晚上都搞不定,像我一樣。(本文伺服器環境:CentOS,nginx-1.4.7,php-5.4.24,CodeIgniter3.0.2--當前最新版本)
404錯誤的原因
原因是預設Nginx不支援pathinfo這種格式,當你瀏覽器裡輸入http:\xxx.xxx.com\index.php\pages\home的時候,Nginx會認為你要訪問index.php目錄下的pages資料夾裡的home,所以會報404 not found錯誤。
解決方法
解決方法肯定是要修改伺服器的重定向規則,大概有兩種思路,一種是改nginx安裝目錄裡的nginx.conf檔案,如果你用了虛擬主機的話就去nginx安裝目錄下的vhosts下找對應的*.conf更改即可。另外一種思路修改CI目錄下的.htaccess檔案,參見:http://blog.csdn.net/freshlover/article/details/8977111
本文是第一種思路。在修改之前先來看下原始的conf檔案:
{
listen 80;
server_name 1.abc.com 2.abc.com;
root /a/domains/1.abc.com/public_html;
index index.html index.htm index.shtml index.php;
error_page 404 /404.html;
#Custom rules Start
#Custom rules End
location = /500. html {
root /usr/share/nginx/html;
}
location ~ \.php$ {
fastcgi_pass unix:/dev/shm/php.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
access_log /a/apps/nginx/logs/1.abc.com.access.log main;
}
location ~ /\.ht {
deny all;
}
}
PS:上面為了隱私,我把server_name改為1.abc.com了,這個對應自己的server_name.
下面介紹修改方法,在修改conf前切記將自己的conf,cp為conf.back備份一份。
下面為修改方法:
1,修改php支援pathinfo
再修改conf之前,找到php的php.ini檔案(可能在php安裝目錄的etc目錄也可能在lib資料夾下,看自己的配置),搜尋:cgi.fix_pathinfo
將註釋放開,並置為1:cgi.fix_pathinfo=1
2,修改conf之前有個問題要明確,那就是CI的根目錄 是不是web的root目錄,如果是的話,如下修改:
只需要增加如下即可:
在location ~ .php$之前增加一段:
if (!-e $request_filename) {
rewrite ^.*$ /index.php last;
}
這個意思是,如果你瀏覽器裡要訪問的檔案不存在時,會自動路由至web根目錄下的index.php進行訪問。
當然上面這段話也可以用下面的來代替:
location / {
try_files $uri $uri/ /index.php;
}
完整的配置為:
server{
listen 80;
server_name 1.sod90.com app.sod90.com;
root /a/domains/1.sod90.com/public_html;
index index.html index.htm index.shtml index.php;
error_page 404 /404.html;
#Custom rules Start
#Custom rules End
location = /500.html {
root /usr/share/nginx/html;
}
#location / {
# try_files $uri $uri/ /index.php;
#}
if (!-e $request_filename) {
rewrite ^.*$ /city52/index.php last;
}
location ~ \.php$ {
fastcgi_pass unix:/dev/shm/php.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
access_log /a/apps/nginx/logs/app.sod90.com.access.log main;
}
location ~ /\.ht {
deny all;
}
}
注意:上面的try_files完全可以代替rewrite,參見連結
除了加這個重定向之外,conf裡不需要再加任何奇奇怪怪的東西。
然後檢查CI的config檔案裡以下三個引數:
$config['base_url'] = 'http://1.abc.com/';
$config['index_page'] = '';
$config['uri_protocol'] = 'REQUEST_URI';
這三個引數比較關鍵,其中第一個是web根目錄對應的域名 ,index_page要為”,不要為預設值 ‘index.php’.
經過以上設定就ok了,url地址裡不需要寫index.php了。
延伸
現在考慮這種情況,如果一個後臺,分支援app和web的,有時候用不同的框架也是在所難免。把所有框架都放在根目錄下也不太好看。如果我的CI的根目錄不是web的根目錄,而是如public_html下的xxx資料夾,此時只需將conf裡的try_files語句里路由的/index.php改為/xxx/index.php即可。如下:
location / {
try_files $uri $uri/ /xxx/index.php;
}
再CI的config.php裡,寫成
$config['base_url'] = 'http://1.abc.com/';
或者:
$config['base_url'] = 'http://app.sod90.com/xxx/';
都是可以的,只要路由對了,就沒問題。但是為了保險起見,base_url如後者比較好,然後url裡就不要再帶index.php了。兩者的區別還體現在當使用CI的函式如base_url()時得到的值將會不一樣。參考連結 。
補充說明,一般來說conf裡如下三句話是關鍵:
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
但是我的conf裡只用了下面一句:
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;