`
yipsilon
  • 浏览: 242246 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

关于URL路由的一些事儿

阅读更多
虽然有人抱怨使用Apache的mod_rewrite在访问量大的时候经常会出现CPU的占用率为 100%的情况,但是对于一些中小型网站来说,这样做毕竟会美化URL,有益于搜索引擎的收录。

因此CMSPAD 1.1的最后一个特性就是支持URL路由(或URL Rewrite?),以下称URLR。那么,CMSPAD是如何支持URLR的呢?下面我们来分析一下URL路径的一些特性。

一个URL由协议、主机、端口、访问路径组成,前三者忽略,说说访问路径吧,它是一个由“/”分隔的一个字符串,用来定位文件位置。正常的一个网站的URL模式为:
http://www.yourcompany.com/index.php

其中“/index.php”就是其访问路径(或叫URI?不知道,自己查查吧)。而好多网站为了隐藏整站程序的实现技术,一般都隐藏了文件后缀,例如:
http://www.yourcompany.com/hello/world/2007/12/20

通过某些URLR技术来进行路径重写到指定脚本文件中。Servlet路径模式匹配和RoR都是这样干的。

因此,如何使用CMSPAD把路径给优化成很不错的感觉呢?其实很简单。

1. 建立一个Dispatcher文件,是PHP的。
<?php
require_once('kernel/global.php'); //包含CMSPAD核心文件
import('Dispatcher'); //导入Dispatcher包
$dispatcher = new Dispatcher('default'); //创建Dispatcher实例,这里使用默认的URLR解析器
$dispatcher->dispatch(isset($_SERVER['PATH_INFO'])?$_SERVER['PATH_INFO']:''); //使用PATH_INFO作为参数进行URLR转换。
?>
当然,如果你不想使用PATH_INFO作为路径转换,可以使用其他的数据,例如GET参数。将文件保存在网站目录下,例如 /index.php。

2. 增加 .htaccess 文件:就是写Apache的URL Rewrite规则,这里就不提了。

3. 新建一个Portlet,如果不知道什么叫Portlet,那就看看偶本博客中以前的文章。
class DefaultPortal extends Portlet{
  public function pageDefaultPortal($params){
    return 'This is home page: '.$params[0];
  }
  public function pageHelloWorld($params){
    return 'This is hello world page: '.print_r($params);
  }
}
看到了没有,所有的URLR方法都是以“page”开头的,并且有个类型为单项数组的参数($params),并返回输出的内容,将代码保存到Portlet主目录下的DefaultPortal.php文件中。

4. 本节就三个字:搞定鸟。

在测试之前,大家需要了解一下CMSPAD URLR的一些路径处理规则:

1. default: 默认的路径处理方法,格式为 /[PortletName]/[PageName]/[Param1[/Param2[...]]]

2. statics: 伪静态页的路径处理方法,格式为:/[PortletName]/[PageName]/[Param1[,Param2[...]]].html

在这里如果没有PageName,那么CMSPAD将自动匹配到与PortletName同名的方法,例如使用默认模式的路径 /SimplePortlet/100/200/300 将被转换为 /SimplePortlet/SimplePortlet/100/200/300。

如果连PortletName也没有,没事儿,CMSPAD可以通过配置信息变量 $_CONFIG['DISPATCH']['PORTAL'] 来作为默认的Portlet使用;如果连 $_CONFIG['DISPATCH']['PORTAL'] 变量都没有定义,也没事儿,系统会自动使用 DefaultPortal 作为Portlet名字来使用;如果连 DefaultPortal 也没定义,那没办法了,系统会返回404错误。

下面就开始测试了:

把Apache服务器打开,假设以上程序在web根目录下,在浏览器中敲入下列地址 http://localhost/index.php/DefaultPortal/100000,你将会看到以下内容:
This is home page: 100000
,而敲入 http://localhost/index.php/DefaultPortal/helloWorld/100/200,则会看到:
This is hello world page: Array([0] => 100, [1] => 200)


而如果使用statics模式,则路径分别为:http://localhost/index.php/DefaultPortal/100000.html 和 http://localhost/index.php/DefaultPortal/helloWorld/100,200.html

这就有个问题了,如果可以任意转换URLR处理器,那么在模板中使用路径时怎么样动态转换路径呢?答案当然是有的啦,哈哈

在模板中,使用hyperlink函数即可实现,例如:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>URL Router Portal Test</title>
</head>
<body>
<!-- 完整的使用方法 1-->
<a href="<{hyperlink portlet="DefaultPortal" page="DefaultPortal" arg1="100" arg2="200"}>">Portal Link 1</a><br/>
<!-- 完整的使用方法 2-->
<a href="<{hyperlink portlet="DefaultPortal" page="helloworld" arg1="100" arg2="200"}>">Portal Link 2</a><br/>
<!-- 最简使用方法,使用当前Portlet的名字,如果没有在Portlet中使用则使用默认的DefaultPortal,方法名与Portlet名字相同 -->
<a href="<{hyperlink arg1="100" arg2="200"}>">Portal Link 3</a><br/>
<!-- 简便使用方法 1,方法名与Portlet名相同 -->
<a href="<{hyperlink portlet="DefaultPortal" arg1="100" arg2="200"}>">Portal Link 4</a><br/>
<!-- 简便使用方法 2,使用当前Portlet的名字,如果没有在Portlet中使用则使用默认的DefaultPortal-->
<a href="<{hyperlink page="helloworld" arg1="100" arg2="200"}>">Portal Link 5</a><br/>
</body>
</html>
这样,当在后台转换URLR路径处理了方法时,则模板中自动应用了新的路径。

使用默认URLR处理器时输出为:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>URL Router Portal Test</title>
</head>
<body>
<a href="/index.php/DefaultPortal/100/200">Portal Link 1</a><br/>
<a href="/index.php/DefaultPortal/helloworld/100/200">Portal Link 2</a><br/>
<a href="/index.php/DefaultPortal/100/200">Portal Link 3</a><br/>
<a href="/index.php/DefaultPortal/100/200">Portal Link 4</a><br/>
<a href="/index.php/DefaultPortal/helloworld/100/200">Portal Link 5</a><br/>
</body>
</html>
而使用statics处理器时输出为:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>URL Router Portal Test</title>
</head>
<body>
<a href="/index.php/DefaultPortal/100,200.html">Portal Link 1</a><br/>
<a href="/index.php/DefaultPortal/helloworld/100,200.html">Portal Link 2</a><br/>
<a href="/index.php/DefaultPortal/100,200.html">Portal Link 3</a><br/>
<a href="/index.php/DefaultPortal/100,200.html">Portal Link 4</a><br/>
<a href="/index.php/DefaultPortal/helloworld/100,200.html">Portal Link 5</a><br/>
</body>
</html>


下面来看看如何开发URLR路径处理器吧:

创建一个名字为 cmspad_router_<文件名字>的类,实现 URLRouter接口,并实现接口里的两个函数:
class cmspad_router_myrule implements URLRouter{
  public function route($pathinfo){
    // 处理并输出路径所对应的内容。
  }

  public function hyperlink($portlet = null, $method = null, $parameters = array()){
    // 生成并返回该规则的URL路径。
  }
}
将以上代码保存到 inc/urlrouters/myrule.php 文件中。然后在创建Dispatcher文件的代码中将
$dispatcher = new Dispatcher('default'); 
改成
$dispatcher = new Dispatcher('myrule'); 
这样,你写的规则就应用上去了。

下面给出当前默认实现(default)的源代码:
<?php
cmspad_import('util.PortletUtil');
class cmspad_router_default implements URLRouter{
  
  private $portal;
  
  public function __construct($portal = 'DefaultPortal'){
    $this->portal = $portal;
  }

  public function route($pathinfo){
    while(strpos($pathinfo,'//') !== false){
      $pathinfo = str_replace('//','/',$pathinfo);
    }
    $pathinfo = trim($pathinfo,' /');
    if(empty($pathinfo)){
      $pathinfo = $this->portal . '/' . $this->portal;
    }
    $arr = explode('/',$pathinfo);
    if(count($arr) > 0){
      $portlet = $arr[0];
      $portletObj = PortletUtil::newObject($portlet);
      if($portletObj === null || $portletObj === false){
        $portletObj = PortletUtil::newObject($portlet = $this->portal);
      }else{
        array_shift($arr);
      }
    }
    if($portletObj === null || $portletObj === false){
      return false;
    }
    if(count($arr) > 0){
      $portletArr = PortletUtil::newMethod($portletObj,'page' . ucfirst($arr[0]));
      if($portletArr === null || $portletArr === false){
        $portletArr = PortletUtil::newMethod($portletObj,'page' . ucfirst($portlet));
      }else{
        array_shift($arr);
      }
      $portletArg = $arr;
    }else{
      $portletArr = PortletUtil::newMethod($portletObj,'page' . ucfirst($portlet));
      $portletArg = array();
    }
    if($portletArr === null || $portletArr === false){
      return false;
    }
    
    $contents = call_user_func($portletArr,$portletArg);
    if($contents){
      echo $contents;
    }
    return true;
  }

  public function hyperlink($portlet = null,$method = null,$params = null){
    global $_CONFIG;
    if(isset($_CONFIG['DISPATCH']['SCRIPT'])){
      $url = $_CONFIG['DISPATCH']['SCRIPT'];
    }else{
      $url = $_SERVER['SCRIPT_NAME'];
    }
    if(!$portlet){
      $portlet = $this->portal;
    }
    if($portlet){
      $url .= ($portlet == $this->portal?'':'/' . $portlet);
      if($method){
        $url .= ($method == $portlet?'':'/' . $method);
      }
      if($params){
        $url .= '/' . implode('/',$params);
      }
    }
    return $url;
  }
}
?>
此代码保存在 inc/urlrouters/default.php 中。
分享到:
评论

相关推荐

    aio-routes:asyncio 的 URL 路由库

    aio-routes Aio-routes 是一个用于 Web 应用程序的 URL 路由库。 它不支持典型的基于模式或正则表达式的路由。 而是在解析 url 时遍历对象。 请参阅下面的示例,了解更多信息Aioroutes 不仅适用于 HTTP,还适用于...

    路由:Nette路由:双向URL转换

    Nette路由:双向URL转换 介绍 路由器负责有关URL的所有事情,因此您不必再考虑它们。 我们将展示: 如何设置路由器,使URL看起来像您想要的 有关SEO重定向的一些注意事项 我们将向您展示如何编写自己的路由器 它...

    还儿童一个健康上网环境,正式开启我的路由器URL网址白名单之旅

    在建立URL白名单这个事情上,因为不了解路由器,所以我走了很多弯路,花费了大量的时间精力和金钱。 前后尝试过华硕RT-AC1900P、华为荣耀pro2、斐讯K2P、TP-LINK企业无线路由器 TL-WAR1200L以及软路由openwrt都不是...

    Vue路由前后端设计总结

    一开始我还以为vue的路由只能用在工程化的项目里面呢,然后研究了一下才发现,在脚本化里面也是可以用的。其实呢不管在哪里用,把原理研究明白就对了。 一、 官网demo 这里不得不吐槽一下官网,写的不清不楚的,在...

    rudy:Rudy Router-适用于react-redux应用程序的MVC样式路由异步控制器

    它可以做的一些事情: 在您选择的URL和Redux操作之间保持双向映射。 就您的应用而言,URL更改是Redux操作,而路由状态是Redux状态。 此映射的工作方式与服务器端和客户端渲染相同。 触发在redux操作(包括但不...

    angular-api-urls:用于管理 API url 的简单角度提供程序

    例子首先用一个简单的安装模块bower install --save angular-api-urls 然后做一些很酷的事情。 有两种配置 API 的方法。 如果您只有一个 API,只需使用APIUrlsProvider参数对其进行配置。 否则,您可以在apis属性中...

    移除AngularJS下URL中的#字符的方法

    AngularJS 默认将会使用一个 # 号来对URL进行路由. 例如:  http://example.com/  http://example.com/#/about  http://example.com/#/contact 要获得干净的URL并将井号从URL中移除是很容易的. 完成两件事情就行了...

    takeme:一个简单有效的路由解决方案

    那时的事情更简单 :rose: 具有简单单向数据流的简单客户端路由解决方案: url ------&gt; ApplicationState ------&gt; YourView :up-left_arrow: :down-left_arrow: navigate | link | browser history 使用 ...

    微信小程序-微信小程序-木棉小镇

    cottonTown 微信小程序-木棉小镇 一个朋友的项目,所有前端代码在这里公开,都是模拟数据,后面的接口将不会更新。 项目主要有以下几个特点: ...开发者不用维护路由,不用管理状态,这些事情微信的框架都帮你做了。

    django-easy-app

    在基于 django 类的视图类上使用新的“路由”属性指定 url 路由的能力。 这使得编写和使用基于类的视图成为可能,而无需理解正则表达式并单独更新 urls.py。 将starteasyapp命令添加到 manage.py 以允许轻松创建...

    精通AngularJS part1

    路由映射URL174 定义路由时指定控制器174 导航的不足175 63使用AngularJS自带的路由服务175 基础路由定义175 显示匹配的路由内容176 匹配灵活的路由177 定义默认路由178 访问路由参数178 多个控制器重用...

    kaizen:基于Flask的Web框架和示例站点

    URL路由是从此处处理的。 每个类都有自己的导入,无需与应用程序的其余部分共享。 Flask-login用于提供身份验证。 Flask-bouncer用于提供授权。 我们通过@linkyndy使用Remodel ORM访问RethinkDB的JSON存储。 像...

    网址匹配:轻松地从网址中提取有趣的信息

    受Clojure的 (一个很棒的路由库)的启发。用法示例from url_match import make_schema , matchyt_be_schema = make_schema ( 'https? youtu.be /:id {t=:ts}' )match ( yt_be_schema , '...

    Vue集成Iframe页面的方法示例

    我们切换为vue框架是后面的事情,之前还有一些功能页面是用jsp页面写的,而我们的管理系统需要既支持Vue的url,又要支持这些发布之后的jsp页面 还有一个就是切换tab回来的时候之前输入的东西还要存在 系统页面截图...

    solar-system-of-js:在JS平台上可视化语言

    幻灯片转换由驱动,以对进行动画增量操作规范使我们可以跳到特定的幻灯片(用于URL路由) 该是应用程序状态的纯函数(基本上)档案说明: 入口点幻灯片过渡状态操作动画实用程序(使用core.async) 画布初始化和api...

    react-router-react16-compatiable:react-router-react16兼容的原始版本^ 2.1.0

    React路由器 兼容16 React... 安装使用npm : $ npm install --save react-router然后使用支持CommonJS或ES2015模块的模块打包器(如webpack) ,像其他任何事情一样使用: // using an ES6 transpiler, like babel

    next-auth-things:用Next.js和auth0做事情

    它试图涵盖一些主题: 登录中登出在服务器端加载用户并将其添加为SSR的一部分( ) 在客户端加载用户并使用快速/缓存的SSR页面( ) 可以加载当前用户的API路由( ) 使用挂钩使用户在整个应用程序中可用( ) 了解...

    mitm-play:使用Playwright的中间人

    中间的人使用Playwright拦截两者之间的流量并为开发人员做很多事情动作表演安装npm install -g mitm-play 使用包含演示路径的路由执行mitm-play命令: mitm-play -rG 例// create file: ~/user-route/keybr....

    serve-webpack-client:帮助程序模块,用于从Node.js服务器提供与Webpack相关的客户端代码

    但是考虑到我通常将它们一起使用需要一些思考: 服务单页应用程序(例如,在ReactJS或AngularJS中) 想要使用HTML5历史记录API来避免URL中的丑陋“#”。 希望使用快递服务器同时提供客户端和后端REST API。 ...

    Food-Market

    食品超市 不在时完成的事情 注册已创建的应用 ...用户数据库已创建 使用CRISPY FORMS创建的用户表单 ...在提交表单重定向到主页上 CRISPY FORM CSS完成 URL路由中的微小更改 聊天聊天消息数据库已创建

Global site tag (gtag.js) - Google Analytics