thinkphp5URL和路由

来源:https://www.cnblogs.com/xiaohuochai/archive/2017/12/26/8110834.html
-Advertisement-
Play Games

[1]URL訪問 [2]參數傳入 [3]隱藏入口 [4]定義路由 [5]URL生成 ...


前面的話

  本文將詳細介紹thinkphp5URL和路由

 

URL訪問

  ThinkPHP採用單一入口模式訪問應用,對應用的所有請求都定向到應用的入口文件,系統會從URL參數中解析當前請求的模塊、控制器和操作,下麵是一個標準的URL訪問格式:

http://domainName/index.php/模塊/控制器/操作

  其中index.php就稱之為應用的入口文件(註意入口文件可以被隱藏,後面會提到)

  模塊在ThinkPHP中的概念其實就是應用目錄下麵的子目錄,而官方的規範是目錄名小寫,因此模塊全部採用小寫命名,無論URL是否開啟大小寫轉換,模塊名都會強制小寫

  應用的index模塊的Index控制器定義如下:

<?php

namespace app\index\controller;

class Index
{
    public function index()
    {
        return 'index';
    }

    public function hello($name = 'World')
    {
        return 'Hello,' . $name . '!';
    }
}

  如果直接訪問入口文件的話,由於URL中沒有模塊、控制器和操作,因此系統會訪問預設模塊(index)下麵的預設控制器(Index)的預設操作(index),因此下麵的訪問是等效的:

http://tp5.com/index.php
http://tp5.com/index.php/index/index/index

  如果要訪問控制器的hello方法,則需要使用完整的URL地址

http://tp5.com/index.php/index/index/hello/name/thinkphp

  訪問URL地址後頁面輸出結果為:

Hello,thinkphp!

  由於name參數為可選參數,因此也可以使用

http://tp5.com/index.php/index/index/hello

  訪問URL地址後頁面輸出結果為:

Hello,World!

  預設情況下,URL地址中的控制器和操作名是不區分大小寫的,因此下麵的訪問其實是等效的:

http://tp5.com/index.php/index/Index/Index
http://tp5.com/index.php/index/INDEX/INDEX

  如果控制器是駝峰的,例如定義一個HelloWorld控制器(application/index/controller/HelloWorld.php):

<?php
namespace app\index\controller;
class HelloWorld
{
    public function index($name = 'World')
    {
        return 'Hello,' . $name . '!';
    }
}

  正確的URL訪問地址(該地址可以使用url方法生成)應該是

http://tp5.com/index.php/index/hello_world/index

  系統會自動定位到HelloWorld控制器類去操作

  如果使用

http://tp5.com/index.php/index/HelloWorld/index

  將會報錯,並提示Helloworld控制器類不存在

  如果希望嚴格區分大小寫訪問(這樣就可以支持駝峰法進行控制器訪問),可以在應用配置文件中設置:

// 關閉URL自動轉換(支持駝峰訪問控制器)
'url_convert' => false,

  關閉URL自動轉換之後,必須使用下麵的URL地址訪問(控制器名稱必須嚴格使用控制器類的名稱,不包含控制器尾碼):

http://tp5.com/index.php/index/Index/index
http://tp5.com/index.php/index/HelloWorld/index

  如果伺服器環境不支持pathinfo方式的URL訪問,可以使用相容方式,例如:

http://tp5.com/index.php?s=/index/Index/index

  其中變數s的名稱的可以配置的

  5.0不再支持普通的URL訪問方式,所以下麵的訪問是無效的,你會發現無論輸入什麼,訪問的都是預設的控制器和操作

http://tp5.com/index.php?m=index&c=Index&a=hello

 

參數傳入

  通過操作方法的參數綁定功能,可以實現自動獲取URL的參數,仍然以上面的控制器為例,控制器代碼如下:

<?php
namespace app\index\controller;
class Index
{
    public function index()
    {
        return 'index';
    }
    public function hello($name = 'World')
    {
        return 'Hello,' . $name . '!';
    }
}

  當我們訪問

http://tp5.com/index.php/index/index/hello

  就是訪問app\index\controller\Index控制器類的hello方法,因為沒有傳入任何參數,name參數就使用預設值World。如果傳入name參數,則使用:

http://tp5.com/index.php/index/index/hello/name/thinkphp

  頁面輸出結果為:

Hello,thinkphp!

  現在給hello方法增加第二個參數:

public function hello($name = 'World', $city = '')
    {
        return 'Hello,' . $name . '! You come from ' . $city . '.';
    }

  訪問地址為

http://tp5.com/index.php/index/index/hello/name/thinkphp/city/shanghai

  頁面輸出結果為:

Hello,thinkphp! You come from shanghai.

  可以看到,hello方法會自動獲取URL地址中的同名參數值作為方法的參數值,而且這個參數的傳入順序不受URL參數順序的影響,例如下麵的URL地址輸出的結果和上面是一樣的:

http://tp5.com/index.php/index/index/hello/city/shanghai/name/thinkphp

  或者使用

http://tp5.com/index.php/index/index/hello?city=shanghai&name=thinkphp

  還可以進一步對URL地址做簡化,前提就是我們必須明確參數的順序代表的變數,我們更改下URL參數的獲取方式,把應用配置文件中的url_param_type參數的值修改如下:

// 按照參數順序獲取
'url_param_type' => 1,

  現在,URL的參數傳值方式就變成了嚴格按照操作方法的變數定義順序來傳值了,也就是說我們必須使用下麵的URL地址訪問才能正確傳入namecity參數到hello方法:

http://tp5.com/index.php/index/index/hello/thinkphp/shanghai

  頁面輸出結果為:

Hello,thinkphp! You come from shanghai.

  如果改變參數順序為

http://tp5.com/index.php/index/index/hello/shanghai/thinkphp

  頁面輸出結果為:

Hello,shanghai! You come from thinkphp.

  顯然不是我們預期的結果。

  同樣,我們試圖通過

http://tp5.com/index.php/index/index/hello/name/thinkphp/city/shanghai

  訪問也不會得到正確的結果

  [註意]按順序綁定參數的話,操作方法的參數只能使用URL pathinfo變數,而不能使用get或者post變數

 

隱藏入口

  可以去掉URL地址裡面的入口文件index.php,但是需要額外配置WEB伺服器的重寫規則。

  以Apache為例,需要在入口文件的同級添加.htaccess文件(官方預設自帶了該文件),內容如下

<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>

  如果用的phpstudy,規則如下:

<IfModule mod_rewrite.c> 
Options +FollowSymlinks -Multiviews 
RewriteEngine on 
RewriteCond %{REQUEST_FILENAME} !-d 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteRule ^(.*)$ index.php [L,E=PATH_INFO:$1] 
</IfModule>

  接下來就可以使用下麵的URL地址訪問了

http://tp5.com/index/index/index
http://tp5.com/index/index/hello

  如果使用的apache版本使用上面的方式無法正常隱藏index.php,可以嘗試使用下麵的方式配置.htaccess文件:

<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L]
</IfModule>

  如果是Nginx環境的話,可以在Nginx.conf中添加:

location / { // …..省略部分代碼
    if (!-e $request_filename) {
        rewrite  ^(.*)$  /index.php?s=/$1  last;
        break;
    }
}

 

定義路由

  URL地址裡面的index模塊怎麼才能省略呢,預設的URL地址顯得有點長,下麵就來說說如何通過路由簡化URL訪問。

  我們在路由定義文件(application/route.php)裡面添加一些路由規則,如下:

return [
    // 添加路由規則 路由到 index控制器的hello操作方法
    'hello/:name' => 'index/index/hello',
];

  該路由規則表示所有hello開頭的並且帶參數的訪問都會路由到index控制器的hello操作方法。

  路由之前的URL訪問地址為:

http://tp5.com/index/index/hello/name/thinkphp

  定義路由後就只能訪問下麵的URL地址

http://tp5.com/hello/thinkphp

  [註意]定義路由規則後,原來的URL地址將會失效,變成非法請求。

  但這裡有一個小問題,如果我們只是訪問

http://tp5.com/hello

  將發生錯誤

  事實上這是由於路由沒有正確匹配到,我們修改路由規則如下:

return [
    // 路由參數name為可選
    'hello/[:name]' => 'index/hello',
];

  使用[]把路由規則中的變數包起來,就表示該變數為可選,接下來就可以正常訪問了

http://tp5.com/hello

  當name參數沒有傳入值的時候,hello方法的name參數有預設值World,所以輸出的內容為 Hello,World!

  除了路由配置文件中定義之外,還可以採用動態定義路由規則的方式定義,例如在路由配置文件(application/route.php)的開頭直接添加下麵的方法:

use think\Route;

Route::rule('hello/:name', 'index/hello');

  完成的效果和使用配置方式定義是一樣的。

  無論是配置方式還是通過Route類的方法定義路由,都統一放到路由配置文件application/route.php文件中

  [註意]路由配置不支持在模塊配置文件中設置

【完整匹配】

  前面定義的路由是只要以hello開頭就能進行匹配,如果需要完整匹配,可以使用下麵的定義:

return [
    // 路由參數name為可選
    'hello/[:name]$' => 'index/hello',
];

  當路由規則以$結尾的時候就表示當前路由規則需要完整匹配。

  當我們訪問下麵的URL地址的時候:

http://tp5.com/hello // 正確匹配
http://tp5.com/hello/thinkphp // 正確匹配
http://tp5.com/hello/thinkphp/val/value // 不會匹配

【閉包定義】

  還支持通過定義閉包為某些特殊的場景定義路由規則,例如:

return [
    // 定義閉包
    'hello/[:name]' => function ($name) {
        return 'Hello,' . $name . '!';
    },
];

  或者

use think\Route;

Route::rule('hello/:name', function ($name) {
    return 'Hello,' . $name . '!';
});

  [註意]閉包函數的參數就是路由規則中定義的變數

  因此,當訪問下麵的URL地址:

http://tp5.com/hello/thinkphp

  會輸出

Hello,thinkphp!

【設置URL分隔符】

  如果需要改變URL地址中的pathinfo參數分隔符,只需要在應用配置文件(application/config.php)中設置:

// 設置pathinfo分隔符
'pathinfo_depr'          => '-',

  路由規則定義無需做任何改變,我們就可以訪問下麵的地址:

http://tp5.com/hello-thinkphp

【路由參數】

  還可以約束路由規則的請求類型或者URL尾碼之類的條件,例如:

return [
    // 定義路由的請求類型和尾碼
    'hello/[:name]' => ['index/hello', ['method' => 'get', 'ext' => 'html']],
];

  上面定義的路由規則限制了必須是get請求,而且尾碼必須是html的,所以下麵的訪問地址:

http://tp5.com/hello // 無效
http://tp5.com/hello.html // 有效
http://tp5.com/hello/thinkphp // 無效
http://tp5.com/hello/thinkphp.html // 有效

【變數規則】

  接下來,嘗試一些複雜的路由規則定義滿足不同的路由變數。在此之前,首先增加一個控制器類如下:

<?php
namespace app\index\controller;
class Blog
{
    public function get($id)
    {
        return '查看id=' . $id . '的內容';
    }
    public function read($name)
    {
        return '查看name=' . $name . '的內容';
    }
    public function archive($year, $month)
    {
        return '查看' . $year . '/' . $month . '的歸檔內容';
    }
}

  添加如下路由規則:

return [
    'blog/:year/:month' => ['blog/archive', ['method' => 'get'], ['year' => '\d{4}', 'month' => '\d{2}']],
    'blog/:id'          => ['blog/get', ['method' => 'get'], ['id' => '\d+']],
    'blog/:name'        => ['blog/read', ['method' => 'get'], ['name' => '\w+']],
];

  在上面的路由規則中,我們對變數進行的規則約束,變數規則使用正則表達式進行定義。

  我們看下幾種URL訪問的情況

// 訪問id為5的內容
http://tp5.com/blog/5 
// 訪問name為thinkphp的內容
http://tp5.com/blog/thinkphp 
// 訪問2015年5月的歸檔內容
http://tp5.com/blog/2015/05 

【路由分組】

  上面的三個路由規則由於都是blog打頭,所以我們可以做如下的簡化:

return [
    '[blog]' => [
        ':year/:month' => ['blog/archive', ['method' => 'get'], ['year' => '\d{4}', 'month' => '\d{2}']],    
        ':id'          => ['blog/get', ['method' => 'get'], ['id' => '\d+']],
        ':name'        => ['blog/read', ['method' => 'get'], ['name' => '\w+']],
    ],
];

  對於這種定義方式,我們稱之為路由分組,路由分組一定程度上可以提高路由檢測的效率

【複雜路由】

  有時候,還需要對URL做一些特殊的定製,例如如果要同時支持下麵的訪問地址

http://tp5.com/blog/thinkphp 
http://tp5.com/blog-2015-05 

  我們只要稍微改變路由定義規則即可:

return [
    'blog/:id'            => ['blog/get', ['method' => 'get'], ['id' => '\d+']],
    'blog/:name'          => ['blog/read', ['method' => 'get'], ['name' => '\w+']],
    'blog-<year>-<month>' => ['blog/archive', ['method' => 'get'], ['year' => '\d{4}', 'month' => '\d{2}']],
];

  對 blog-<year>-<month> 這樣的非正常規範,我們需要使用<變數名>這樣的變數定義方式,而不是 :變數名方式。

  簡單起見,我們還可以把變數規則統一定義,例如:

return [
    // 全局變數規則定義
    '__pattern__'         => [
        'name'  => '\w+',
        'id'    => '\d+',
        'year'  => '\d{4}',
        'month' => '\d{2}',
    ],
    // 路由規則定義
    'blog/:id'            => 'blog/get',
    'blog/:name'          => 'blog/read',
    'blog-<year>-<month>' => 'blog/archive',
];

  在__pattern__中定義的變數規則我們稱之為全局變數規則,在路由規則裡面定義的變數規則我們稱之為局部變數規則,如果一個變數同時定義了全局規則和局部規則的話,當前的局部規則會覆蓋全局規則的,例如:

return [
    // 全局變數規則
    '__pattern__'         => [
        'name'  => '\w+',
        'id'    => '\d+',
        'year'  => '\d{4}',
        'month' => '\d{2}',
    ],

    'blog/:id'            => 'blog/get',
    // 定義了局部變數規則
    'blog/:name'          => ['blog/read', ['method' => 'get'], ['name' => '\w{5,}']],
    'blog-<year>-<month>' => 'blog/archive',
];

 

URL生成

  定義路由規則之後,可以通過Url類來方便的生成實際的URL地址(路由地址),針對上面的路由規則,我們可以用下麵的方式生成URL地址。

// 輸出 blog/thinkphp
Url::build('blog/read', 'name=thinkphp');
Url::build('blog/read', ['name' => 'thinkphp']);
// 輸出 blog/5
Url::build('blog/get', 'id=5');
Url::build('blog/get', ['id' => 5]);
// 輸出 blog/2015/05
Url::build('blog/archive', 'year=2015&month=05');
Url::build('blog/archive', ['year' => '2015', 'month' => '05']);

  [註意]build方法的第一個參數使用路由定義中的完整路由地址

  還可以使用系統提供的助手函數url來簡化

url('blog/read', 'name=thinkphp');
// 等效於
Url::build('blog/read', 'name=thinkphp');

  通常在模板文件中輸出的話,可以使用助手函數,例如:

{:url('blog/read', 'name=thinkphp')}

  如果我們的路由規則發生調整,生成的URL地址會自動變化

  如果你配置了url_html_suffix參數的話,生成的URL地址會帶上尾碼,例如:

'url_html_suffix'   => 'html',

  那麼生成的URL地址 類似

blog/thinkphp.html 
blog/2015/05.html

  如果你的URL地址全部採用路由方式定義,也可以直接使用路由規則來定義URL生成,例如:

url('/blog/thinkphp');
Url::build('/blog/8');
Url::build('/blog/archive/2015/05');

  生成方法的第一個參數一定要和路由定義的路由地址保持一致,如果你的路由地址比較特殊,例如使用閉包定義的話,則需要手動給路由指定標識,例如:

// 添加hello路由標識
Route::rule(['hello','hello/:name'], function($name){
    return 'Hello,'.$name;
});
// 根據路由標識快速生成URL
Url::build('hello', 'name=thinkphp');
// 或者使用
Url::build('hello', ['name' => 'thinkphp']);

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 閱讀目錄: 主機安裝 集群搭建 API 操作 API 說明和 etcdctl 命令說明 "etcd" 是 CoreOS 團隊發起的一個開源項目(Go 語言,其實很多這類項目都是 Go 語言實現的,只能說很強大),實現了 分散式鍵值存儲 和 服務發現 ,etcd 和 ZooKeeper/Consul ...
  • 原文地址:http://www.woshipm.com/pmd/160822.html+ 支付寶系統架構概況 典型處理預設 資金處理平臺 財務會計 支付清算 核算中心 交易 柔性事務 支付寶的開源分散式消息中間件–Metamorphosis(MetaQ) Metamorphosis (MetaQ) ... ...
  • 轉碼對於普通用戶來說不可見的,但卻是短視頻SDK的一個重要過程。 ...
  • 當前環境:Windows 7 64位 ps:本博客都是基於Windows,Linux請繞行~ 1.下載Python 安裝包 官網地址 選擇適合自己的安裝包,當前最高版本Python 3.X 2.下載適合自己的Ide,比如 VisualStudio、VS Code、WingIDE、Vim、Pychar ...
  • ASP.NET WebAPI使用Swagger生成測試文檔 SwaggerUI是一個簡單的Restful API測試和文檔工具。簡單、漂亮、易用(官方demo)。通過讀取JSON配置顯示API .項目本身僅僅也只依賴一些html,css,js靜態文件.你可以幾乎放在任何Web容器上使用 搗鼓了好久最 ...
  • 本文作者在一年之內參加過多場面試,應聘崗位均為 Java 開發方向。在不斷的面試中,分類總結了 Java 開發崗位面試中的一些知識點。 主要包括以下幾個部分: 面試,是大家從學校走向社會的第一步。 互聯網公司的校園招聘,從形式上說,面試一般分為 2-3 輪技術面試 +1 輪 HR 面試。但是一些公司 ...
  • 在定義泛型時,我們可以通過extends來限定泛型類型的上限,也可以通過super來限定下限,這兩個限定字一般會和?等關鍵字搭配使用。 比如有這樣的代碼List<? super Father> dest,這裡,super包含“高於”的意思,? Super Father就表示dest存放的對象應當“以 ...
  • 本文詳細分析了Spring boot實現的一個web版的Hello World,通過Hello world這樣一個簡單的例子,詳細講解了Spring boot的基本操作,並對對Spring boot的原理做了相應的分析。 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...