| 通配符 | 匹配 | 範例 |
:num | 純數字段落 | 'product/:num' → 'catalog/product_lookup/$1' |
:any | 任意字元 (含 /) | 'page/:any' → 'cms/view_page/$1' |
$route['user/(:num)'] = 'user/profile/$1'; // /user/123 -> User::profile(123)
$route['blog/(:any)'] = 'blog/post/$1'; // /blog/my-first-post -> Blog::post('my-first-post')
3. 正則表達式 (PCRE)
鍵名使用正則,**捕獲組** 對應 $1, $2...:
$route['^api/v(\d+)/(.+)$'] = 'api/v$1/$2'; // /api/v2/users -> api/v2/users
$route['^([a-z]{2})/(.+)$'] = '$2/set_lang/$1'; // /en/products -> products/set_lang/en
4. 回調函數 (CI 3.1+)
支援匿名函數動態決定路由:
$route['products/(:any)'] = function($slug) {
// 檢查 slug 是否為分類還是商品
if ($this->Category_model->exists($slug)) {
return 'category/view/' . $slug;
}
return 'product/detail/' . $slug;
};
實戰案例集
案例 1:舊版 .html 網址無縫遷移
需求:/product_123.html → /product/detail/123
// 錯誤寫法:查詢字串不支援
// $route['product_(:num).html'] = 'product/detail?$1'; // 404!
// 正確寫法:補上尾隨斜線確保段落解析正確
$route['product_(:num).html'] = 'product/detail/$1/';
// 控制器方法
public function detail($id) {
// 參數自動從 URI 最後一段獲取
// 或手動處理 $_GET (需 parse_str)
parse_str(ltrim($this->uri->uri_string(), '?'), $_GET);
}
案例 2:RESTful API 版本控制
$route['api/v1/users'] = 'api/v1/users/index';
$route['api/v1/users/(:num)'] = 'api/v1/users/show/$1';
$route['api/v1/users/(:num)/posts'] = 'api/v1/users/posts/$1';
// 使用正則統一處理
$route['^api/v(\d+)/(.+)$'] = 'api/v$1/$2';
案例 3:多語系網址前綴
$route['^([a-z]{2})/(.+)$'] = '$2/set_lang/$1'; // /en/about -> about/set_lang/en
$route['^([a-z]{2})$'] = 'home/set_lang/$1'; // /en -> home/set_lang/en
// 控制器
public function set_lang($lang) {
$this->session->set_userdata('lang', $lang);
redirect($this->agent->referrer());
}
案例 4:後台管理區域隔離
$route['admin'] = 'admin/dashboard';
$route['admin/(:any)'] = 'admin/$1'; // 所有 /admin/* 導向 admin/ 控制器
// 目錄結構
// controllers/admin/Dashboard.php
// controllers/admin/Users.php
// 類別名: Admin_Dashboard, Admin_Users (需設定 $route['translate_uri_dashes'] = TRUE 或手動映射)
案例 5:維護模式與條件路由
if (ENVIRONMENT === 'maintenance') {
$route['(:any)'] = 'maintenance/index'; // 所有請求導向維護頁
} elseif (config_item('maintenance_mode')) {
// 允許白名單 IP 通過
$whitelist = ['127.0.0.1', '192.168.1.100'];
if (!in_array($_SERVER['REMOTE_ADDR'], $whitelist)) {
$route['(:any)'] = 'maintenance/index';
}
}
路由解析優先序與除錯
優先序規則
- **定義順序優先**:陣列越前面優先匹配
- **具體優於通用**:靜態路由 > 通配符 > 正則 > 回調
- **目錄結構**:
controllers/admin/Users.php 實際類別為 Admin_Users
除錯技巧:在 MY_Controller 印出解析結果
class MY_Controller extends CI_Controller {
public function __construct() {
parent::__construct();
if (ENVIRONMENT === 'development') {
log_message('debug', 'Route: ' . json_encode([
'directory' => $this->router->fetch_directory(),
'class' => $this->router->fetch_class(),
'method' => $this->router->fetch_method(),
'uri_string'=> $this->uri->uri_string(),
]));
}
}
}
常見 404 排查清單
- 檢查
default_controller 拼寫 (區分大小寫)
- 確認
.htaccess 正確移除 index.php
- Apache
AllowOverride All、Nginx try_files 配置
- 控制器檔名/類別名大小寫 (Linux 區分大小寫)
- 方法名是否為
_ 開頭 (私有方法不可路由)
進階:路由快取與效能
CI 每請求解析路由,大型專案路由規則超過 100 條會有微小效能影響。可採用:
// 在 routes.php 末尾快取編譯後的路由
if (ENVIRONMENT === 'production') {
$cache_file = APPPATH . 'cache/routes.php';
if (!file_exists($cache_file) || filemtime($cache_file) < filemtime(__FILE__)) {
file_put_contents($cache_file, '
總結
CodeIgniter 路由系統簡單而強大,核心掌握三點:
- 靜態 > 通配符 > 正則 > 回調 定義順序決定優先權
- 通配符 :num/:any 滿足 90% 需求,複雜場景用正則捕獲組
- 善用除錯輸出 確認實際解析到的控制器/方法
路由配置應集中在 routes.php,**避免依賴 Web Server Rewrite 規則**,確保框架層面可控、可測、可遷移。
- 上一篇文章: CodeIgniter Session 深度解析:原理、配置陷阱與替代方案
- 下一篇文章: CodeIgniter config.php 核心配置項深度解析與動態修改技巧
Copyright ©
程式碼之家 All Rights Reserved