1. 程式人生 > >當CodeIgniter遇到Nginx報404錯誤的解決辦法

當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;