一 什么是路由
路由(routing)是指分组从源到目的地时,决定端到端路径的网络范围的过程.
**这是TCP/IP协议第三层网络层的概念.routing and switching ,cisco,TCP/IP ,网络通信 忆往昔峥嵘岁月啊.
引申到web开发,路由是对特定形式的URL结构进行处理的过程.for example, 从输入地址'https://www.baidu.com/index.php?tn=monline_3_dg' 到服务器返回html的过程.首先,浏览器查找自身页面缓存,cache-control,解析服务器地址,windows 不开代理的情况下,优先查找自己的host文件,然后查找系统的dns缓存,然后查找局域网dns缓存(dnslookup一会局域网交换机或者路由器会有一定的缓存,局域网的DNS服务器),然后查找ISP的dns缓存,然后顶级域名服务器查找,返回对应的A记录之后,向ip地址发出请求,请求有多种方法,GET/POST/PUT/DELETE 等,一般浏览器的请求会带上自己的头部,里面会有一些os 等字段信息,到达ip地址的服务器之后,查找对应的4层端口一般为80,这个端口的listen 的server_name,根据server 下的.htaccess和 rewrite rule 解析文件是否可以访问,php 的文件交给fast-cgi解析,fpm机制保证了性能,opcache代码缓存,如果是静态文件直接返回,脚本文件SSI之后,处理是否server端的缓存,(redis,memcahe),之后文件缓存,smarty缓存,中间还有代码缓存,解析完成返回html给请求端,请求端render html和css,JS文件由JSengine解析处理. 个人觉得这就是路由流程.可能中间还有一些其他的机制,查找querystring ,请求到服务器之后保存的地址,log,以及服务器存储,内存,硬盘读写等,往深了去想还有内存分配的字段以及垃圾回收等.(web开发真TM是个大池子啊).
总之,路由处理的核心就是浏览器的URI指向到服务器端文件的过程.
二 路由方式
1.正常路由.PoC index.php?action=list&id=1,2,3
2.伪静态. rewrite url ,htaccess PoC index.php/list/1,2,3
3.pathinfo . 需要服务器支持,$_SERVER['pathinfo'], index.php/list/1
** 开启rewrite 功能
1 <Directory /> 2 Options FollowSymLinks 3 AllowOverride None 4 </Directory>
** 开启path_info
1 Options Indexes FollowSymLinks 2 AcceptPathInfo On
$_SERVER['path_info'] 的值是脚本文件到QUERY_STRING 之间的路径部分.
$_SERVER['REQUEST_URI'] 是URL域名之后的部分.
三 简单实现.
指导思想: 所有请求经过伪静态的服务器规则之后,进入index.php入口文件,经过框架入口调用路由,符合路由规则的按照规则分发,不符合的正常分发.
伪码. $_SERVER['REQUEST_URI'] 出pathinfo 和querystring;
1 class sina_router{ 2 public function __construct(){ 3 $res = $this->_get_URI(); //取出pathinfo的信息 4 $this->_uri_to_path($res); 5 } 6 public function _get_URI(){ 7 8 if(!isset($_SERVER['REQUEST_URI']) || !isset($_SERVER['SCRIPT_NAME'])){ 9 return ''; 10 } 11 $uri = $_SERVER['REQUEST_URI']; 12 if(strpos($_SERVER['REQUEST_URI'],$_SERVER['SCRIPT_NAME'])===0){ 13 $uri = substr($uri,strlen($_SERVER['SCRIPT_NAME'])); 14 } 15 $patt = '/?/'; 16 $part = preg_split($patt,$uri,2); 17 $uri = $part[0]; 18 if(isset($part[1])){ 19 $_SERVER['QUERY_STRING'] = $part[1]; 20 parse_str($_SERVER['QUERY_STRING'],$_GET); 21 }else{ 22 $_SERVER['QUERY_STRING'] = $part[0]; 23 $_GET = array(); 24 } 25 if ($uri == '/' || empty($uri)) 26 { 27 return '/'; 28 } 29 $uri = parse_url($uri,PHP_URL_PATH); 30 return str_replace(array('//', '../'), '/', trim($uri, '/')); 31 } 32 33 public function _uri_to_path($path){ 34 $arr = explode('/',$path); 35 $class = array_shift($arr); 36 $method = array_shift($arr); 37 $cnt = count($arr); 38 $i=0; 39 while(($i<$cnt) && count($arr)%2===0){ 40 $_GET[$arr[$i]]=$arr[$i+1]; 41 $i+=2; 42 } if(!file_exists(APP_PATH.'Controller'.DIRECTORY_SEPARATOR.$class.EXT)){ 43 exit('类文件不存在'); 44 } 45 require_once(APP_PATH.'Controller'.DIRECTORY_SEPARATOR.$class.EXT); 46 $obj =new $class; 47 if(!method_exists($obj,$method)){ 48 exit('方法不存在!'); 49 } 50 $obj->$method(); 51 } 52 }
搞定.
贴下我的目录结构.
如果各位有其他实现思路,不妨留言探讨.-:)-:)-:)