15. Magento路由分发过程解析(四):请求重写
Magento请求重写的目的是在路由对象迭代之前,更改请求对象的请求信息。本质上来说,Magento请求重写允许你更改路由对象需求的路径信息,这就意味着,你可以使用重写系统将一个请求从原本的地址(404页面)重新定位到另外一个地址。
请求重写的类型
Magento请求重写系统包含两个部分。第一部分是基于数据库的路由重写规则,通过core/url_rewrite模型类调用。第二部分通过添加在config.xml配置文件中的一系列重写规则完成的。
当然,这两种不同的请求重写内容,拥有一致的目的,只是实现的方式不同而已。
基于模型(数据库)的重写
基于模型的请求重写过程的第一步就是要确定该请求是否需要被重写。这一步通过实例化core/url_rewrite模型,并使用请求对象的路径信息,作为模型中的request_path属性,进行读取。下面主要来分析请求重写模型类的rewrite()方法。略过糟粕,直击重点。
$requestCases = array();
$pathInfo = $request->getPathInfo();
$origSlash = (substr($pathInfo, -1) == '/') ? '/' : '';
$requestPath = trim($pathInfo, '/');$altSlash = $origSlash ? '' : '/'; // If there were final slash - add nothing to less priority paths. And vice versa.
$queryString = $this->_getQueryString(); // Query params in request, matching "path + query" has more priority
if ($queryString) {
$requestCases[] = $requestPath . $origSlash . '?' . $queryString;
$requestCases[] = $requestPath . $altSlash . '?' . $queryString;
}
$requestCases[] = $requestPath . $origSlash;
$requestCases[] = $requestPath . $altSlash;
这一部分实际上是获取对象中的路径信息,然后根据url地址最后是否包含’/’以及?参数,将该请求的路径信息转换为两种或四种url变体格式,以适应用户在输入url的时候的各种可能性。$requestCases数组的最终值可能如下,
sony-vaio-vgn-txn27n-b-11-1-notebook-pc.html/
sony-vaio-vgn-txn27n-b-11-1-notebook-pc.html
sony-vaio-vgn-txn27n-b-11-1-notebook-pc.html/?thisparams=1
sony-vaio-vgn-txn27n-b-11-1-notebook-pc.html?thisparams=1
PS:上面这段代码实际上算是Magento比较容易理解的。但是从编程的角度来说,上面判断并保存四种url的代码可谓经典,特别是判断结尾是否包含‘/’的那段。
在基于数据库的重写规则来看,上述的四种url地址实际上的指向是一致的。也就是说用户可能会输入它们中的任何一个到浏览器中进行访问,而店铺管理员也可能设置它们中的任意一个。所以这里需要对请求路径进行一些处理,然后在继续寻找可能的匹配。当获取到$requestCases数组之后,系统尝试使用该值读取数据库。下面一段我们先跳出rewrite()方法,看下loadByRequestPath()方法。
public function loadByRequestPath($path)
{
$this->setId(null);
$this->_getResource()->loadByRequestPath($this, $path);
$this->_afterLoad();
$this->setOrigData();
$this->_hasDataChanges = false;
return $this;
}
可以看到,该方法内部调用了资源模型,并通过资源模型内部的同名方法在数据库中进行匹配。那我们下面着重来看重写规则的资源模型类下的loadByRequestPath()方法。
public function loadByRequestPath(Mage_Core_Model_Url_Rewrite $object, $path)
{if (!is_array($path)) {
$path = array($path);
}$pathBind = array();
foreach ($path as $key => $url) {
$pathBind['path'.$key] = $url;
}
// Form select
$read = $this->_getReadAdapter();
$select = $read->select()
->from($this->getMainTable())
->where($this->getMainTable() . '.request_path IN (:' . implode(', :', array_flip($pathBind)) . ')')
->where('store_id IN(?)', array(0, (int)$object->getStoreId()));$items = $read->fetchAll($select, $pathBind);
该方法是请求重写模型的模型资源类,很简单,大概行程如下的查询语句,
SELECT `core_url_rewrite`.*
FROM `core_url_rewrite`
WHERE
(request_path IN (:path0, :path1))
AND
(store_id IN(0, 1))
上面的`$pathBind`数组通过请求重写模型传递来的$path参数构建,包含了url的可能的两种或四种变体。该数组根据select语句需求的格式,重新构建了,包含键(path0)及值(请求路径变体)的$pathBind数组。然后在select语句中,通过implode()及array_flip()函数构建查询语句需求的”:path0,:path1″格式。
另外,注意到上述select语句中对于store_id的判断,0肯定是管理员界面,这里按时请求重写也能够应用于管理员界面。1,肯定就是当前的店铺ID了,因为Magento允许为不同商铺的不同地址设置重写规则。
读取正确的重写信息
多个店铺ID以及多个重写路径变体导致了一个问题。查询语句获取到的$items可能包含最多四行记录。也就是说,获取该结果之后,我们还需要确定哪一个$item是正确的。Mangento通过一系列复杂的逻辑,实现了一个优先级系统,并通过该算法最终决定哪个一$item是最匹配的。该部分代码如下,
// Go through all found records and choose one with lowest penalty - earlier path in array, concrete store
$mapPenalty = array_flip(array_values($path)); // we got mapping array(path => index), lower index - better
$currentPenalty = null;
$foundItem = null;
foreach ($items as $item) {
$penalty = $mapPenalty[$item['request_path']] << 1 + ($item['store_id'] ? 0 : 1);
if (!$foundItem || $currentPenalty > $penalty) {
$foundItem = $item;
$currentPenalty = $penalty;
if (!$currentPenalty) {
break; // Found best matching item with zero penalty, no reason to continue
}
}
}
PS:这部分代码涉及到位运算以及二进制的运算。超出了我的只是范围,略过,但是如果进行匹配已经如何匹配就是发生在这里。
当然,我们还是需要了解该算法是如何实现优先级匹配的。我们回到最初的问题,原始请求路径的格式可能如下所示,
/electronice/cell-phones.html/electronice/foo/然后在请求重新模型中,会考虑到url的变体,于是为上面的url分别生成以下变体,/electronice/cell-phones.html//electronice/foo
另外,除了url变体之外,我们还有不同的店铺id,一个真实的店铺id,一个控制台id(0)。这样的话,两两组合,最终可能会有四种返回。即,当读取一个url重写时,Magento可能会按以下顺序返回四个结果,A URL in its Natural state, with the Admin Store IDA URL in its Natural state, with the Non-Admin Store IDA URL in its adulterated state, with the Admin Store ID setA URL in its adulterated state, with the Non-Admin Store ID set好了,基本分析结束,稍等下回到请求重写的rewrite()的方法中去。
应用重写信息
回到rewrite()方法中,我们略过那段对于没有获取到正确重新信息的代码,直接进入下面一段。
01$request->setAlias(self::REWRITE_REQUEST_PATH_ALIAS, $this->getRequestPath());一切征程获取到了正确的重写信息之后,接着使用core/url_rewrite模型的request_path属性给请求对象设置一个别名(alias)。请求对象可以包含无数个别名,成键值对。这些别名告诉请求对象,尽管它拥有一个路径信息,但该路径信息并非是直接从HTTP请求中获取的。
Ghosts of Apache
接着,分析如下代码,
$external = substr($this->getTargetPath(), 0, 6);
$isPermanentRedirectOption = $this->hasOption('RP');
if ($external === 'http:/' || $external === 'https:') {
if ($isPermanentRedirectOption) {
header('HTTP/1.1 301 Moved Permanently');
}
header("Location: ".$this->getTargetPath());
exit;
} else {
$targetUrl = $request->getBaseUrl(). '/' . $this->getTargetPath();
}
//var_dump($this->getTargetPath());exit();
如果说,我们获取到的目标路径是一个完整的url地址,包含http://或者https://,Magento系统会立刻进行http转向,而不是通过内部的请求重写。
15. Magento路由分发过程解析(四):请求重写相关推荐
- Django 路由分发
Django 路由分发 当一个url请求过来之后 1.先到项目主目录下的urls内. 2.由这个url做处理分发给其他app内的urls. 一级路由:主目录urls内引入include from dj ...
- Web框架之Django_03 路由层了解(路有层 无名分组、有名分组、反向解析、路由分发 视图层 JsonResponse,FBV、CBV、文件上传)
阅读目录 一.路由层:(Django的路由系统) 二.伪静态网页和虚拟环境: 三.FBV与CBV.JsonResponse.文件上传 一.路由层:(Django的路由系统) URL配置(Django项 ...
- django ajax 更新表格_Django(反向解析,路由分发、名称空间、视图层、虚拟环境、Django版本、json,CBV)...
https://www.zhihu.com/video/1249117508688711680 每日测验 """ 今日考题 1.列举你知道的orm数据的增删改查方法 2. ...
- 【androidx86 5.1.1】Android HttpClient请求过程解析(上)
Android HttpClient请求过程解析 前言:很久没有写源码解析相关的文章了,所谓"三天不写,上房揭瓦",这都仨月啦!前段时间忙着发版,经理有别的事情忙,就把管理发版的事 ...
- Django学习之路由分发和反向解析
原 Django学习之路由分发和反向解析 2018年07月12日 14:04:55 huangql517 阅读数 519 1>路由分发 我们之前学习的路由配置都是在项目的全局控制文件(项目名称目 ...
- djang urls.py 无名有名分组,反向解析,路由分发,名称空间,伪静态,虚拟环境,django版本...
路由层 路由匹配:APPEND_SLASH = False , 取消自动补全 , settings.py 中添加字段即可 若url尾部为书写/ , django内部会自动补全 urls.py 中 对应 ...
- Drf从入门到精通四(Drf请求与响应、Drf能够解析的请求编码与响应编码、Drf视图、Drf视图基类)
文章目录 一.Drf请求与响应 1.Request类和Response类 2.Drf能够解析的请求编码与相应编码 二.Drf视图组件 四.Drf视图基类 1.基于APIView写5个接口 2.基于Ge ...
- 客快物流大数据项目(十四):DockerFile介绍与构建过程解析
目录 DockerFile介绍与构建过程解析 一.什么是Dockerfile 1.介绍 2.Dockerfile构建步骤
- Express实现路由分发控制、RESTful API
Express实现路由分发控制.RESTful API 标签(空格分隔): Node.js 最近在用Express作为自己的WEB应用框架,其中最为迷惑的就是Express的路由控制和分发,在网上搜了 ...
- Django讲课笔记07:设置路由分发规则
文章目录 零.本讲学习目标 一.课程导入 (一)复习 (二)路由 二.新课讲授 (一)设置路由分发规则 1.创建应用的路由文件(子路由) - urls.py (1)创建index应用的路由文件 (2) ...
最新文章
- oracle本地验证,Oracle 本地验证和密码文件
- hdu A + B Problem II(大数相加,数组实现)
- php fastcgi进程启动,Shell脚本实现启动PHP内置FastCGI Server
- 服务器json文件怎么创建对象,JavaScript中对JSON对象的基本操作示例
- 特别的520,送给特别的你们,还不来看看?
- 信息学奥赛一本通 1162:字符串逆序
- Razor 视图引擎学习
- tomcat 9 无法启动_运维常见问题汇总tomcat篇
- 【yarn】INFO ipc.Client Retrying connect to server xxx 8032 Already tried 0 time(s)
- python吃香吗_python编程为何这么吃香
- LibMesh 数据结构类
- 带有记忆的菲波那切数列
- iphone7 无法连接计算机看照片,iphone7连接电脑没反应怎么解决
- 公开密匙(public key)和专用密匙(private key)
- 致远互联蜂巢计划3.0:三维进化的协同创新生态
- 2008年世界各国GDP排名
- 01-JAVA基础—>赏金任务—>三色球问题
- App应用字体大小保持固定以及关于Configuration的变化
- 电脑视频加水印软件 视频消重
- Kubernetes资源调度之污点与Pod容忍度