Nginx 實現 pathinfo 模式

使用過 ThinkPHP 框架開發應用的同窗應該都會知道,它有一種 URL 模式是 pathinfo,看起來相似下面的 URL:php

http://example.com/module/controller/action/key1/value1/key2/value2.html

其實上面的 URL 的原型是下面的樣子:html

// 這個纔是正宗的 URL,上面那個是冒牌的
http://example.com/index.php?m=module&c=controller&a=action&key1=value1&key2=value2

既然 pathinfo 模式的 URL 不是正宗的,那爲何不用正宗的呢,用正宗的很差嗎?相對於正宗的 URL,pathinfo 模式的確實是有優點的,如下簡單列舉幾項它的好處。nginx

  • 它提供了最好的SEO支持
  • 能夠實現 URL 的僞靜態
  • 它看起來更簡潔、更好看

pathinfo 模式的 URL 有這麼多優勢,那咱們確定要支持了。ThinkPHP 更多的 URL 模式配置及實現,能夠參考這篇文檔。正則表達式

本文主要討論的是 pathinfo 模式的 URL 在 Nginx 中的實現,ThinkPHP 官方文檔中沒有介紹,可是它實現起來也挺簡單的。如下是實現過程的一些思考。服務器

一個標準的通用的 URL 格式是相似下面那樣子的:框架

<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>

參照通用的 URL 格式,對比能夠發現,pathinfo 模式的相對於標準模式的 URL,有兩個地方的區別比較大,一個是沒有了 index.php 文件,另外一個是查詢參數並無使用符號「?」隔開。code

如今要作的就是在 Nginx 接收的 pathinfo 模式的 URL 請求時,將它還原成標準的 URL 模式,這樣服務器就能正常處理了。server

把缺失的 index.php 文件補上htm

這個須要用到 Nginx 的 rewrite 指令,它的做用是將請求的 URI 替換成目標 URL。在這裏須要達到的效果是,將ip

http://example.com/module/controller/action/key1/value1/key2/value2.html

替換成

http://example.com/index.php/module/controller/action/key1/value1/key2/value2.html

固然,並非全部的 URI 都會進行此規則的重寫,只有那些不是文件的 URI 才進行重寫。因此,關於重寫的指令將會相似下面的:

# 若是請求的文件不存在,則進行 URI 重寫
# 在原有的基礎上添加入口文件 index.php
if (!-e $request_filename) {
    rewrite ^/(.*)$ /index.php/$1 last;
}

經過以上配置就能達到補全 index.php 入口文件的效果了。

區分符號 ?先後的內容

在通用的 URL 中,符號「?」是具備特殊做用的,它是用來將查詢字符串和前面的文件隔開。在 pathinfo 模式的 URL 中,符號「?」沒有了,也就是說,服務器沒法區分 URI 中哪些是文件,哪些是查詢字符串了。因此,咱們的目的是將 pathinfo 模式中原本應該由符號「?」區分的內容給手動區分開來。

還好,Nginx 中有個指令能夠實現咱們的目的,fastcgi_split_path_info。它能夠將正則表達式定義的兩個串分別賦值給變量 $fastcgi_script_name 和變量 $fastcgi_path_info,以供後文使用。更多關於 fastcgi_split_path_info 的信息,請查閱這裏

相關配置相似下面的代碼:

location ~ ^(.+\.php)(.*)$ {
    root /var/www/html/$vhost_path;
    fastcgi_pass   phpfpm:9000;
    fastcgi_split_path_info       ^(.+\.php)(.*)$;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO       $fastcgi_path_info;

    include        fastcgi_params;
}

一個簡單的例子

經過上面兩部份的配置,如今的 Nginx 服務器已經支持 pathinfo 模式的 URL 了,如下是一個簡單的 server 配置,僅供參考:

server {
    listen       80;
    server_name  tp5.loc;

    set $vhost_path tp5/public;

    location / {
        root   /usr/share/nginx/html/$vhost_path;
        index  index.php index.html index.htm;

        if (!-e $request_filename) {
            rewrite ^/(.*)$ /index.php/$1 last;
        }
    }

    location ~ ^(.+\.php)(.*)$ {
        root /var/www/html/$vhost_path;
        fastcgi_pass   phpfpm:9000;
        fastcgi_split_path_info       ^(.+\.php)(.*)$;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO       $fastcgi_path_info;

        include        fastcgi_params;
    }
}
相關文章
相關標籤/搜索