Nginx try_files syntax

今天在一台很久不用的服务器上测试 Magento search result page,URL /catalogsearch/result/?q=searchword,发现它不工作,但其他页面正常。这个症状让我联想到以前碰到的类似问题,Magento 无法获得 query_string,所以含问号的 URL 都不能处理,页面重定向到 referring URL。应该是 server rewrite 规则没有写正确,我想。打开 nginx 的配置文件一看,果然,当中一条规则用的是很久以前的写法,后来在不同的服务器上几经改进,production server 都已经用上了新规则。

新规则的写法:


location @magento {
root $php_script_root;
index index.php;
if ($uri ~ ^/(media|js|skin)/) {
break;
}
if (!-e $request_filename) {
rewrite .* /index.php last;
}
}

而老规则的写法:


location @magento {
root $php_script_root;
index index.php;
if ($uri ~ ^/(media|js|skin)/) {
break;
}
try_files $uri $uri/ /index.php;
}

效果略有区别,我在 Difference of try_files to rewrite in Nginx 文章里有提及。不过,今天我还有一个新发现。

我倾向于使用简介语法,try_files 就比 rewrite 简洁得多,难道 try_files 就没有办法应付带问号的 URL 吗?非也,是我不知道 Nginx 原本可以这么奥妙——用 $args 变量!

因此,最新一条完美规则出炉了:


location @magento {
root $php_script_root;
index index.php;
if ($uri ~ ^/(media|js|skin)/) {
break;
}
try_files $uri $uri/ /index.php?$args;
}

Difference of try_files to rewrite in Nginx

try_files 是 Nginx 自0.6.36 新增的 directive。通常对 try_files 的理解是——它是
if (!-e $request_filename) {
rewrite .* /index.php;
}

的更简洁的表达。但我发现它们之间还是略有区别,主要表现在两点:

  1. 如使用 rewrite,Nginx 要求 document_root 下必须有一个 index 文件,即使我把另一个目录别名整个 document_root,但因为 Nginx 先校验 document_root 下是否有一个 index 文件,所以得放置一个空 index 文件。try_files 则没有 index 文件校验,直接去第二、第三… document_root 找对应的文件。
  2. 如使用 try_files $uri $uri/ /index.php,index.php 不能取得 get 变量,例如在 Magento 下,对 http://mydomain/catalogname?mode=list 的访问不能起效,Nginx 交付的页面是 http://mydomain/catalogname。这时必须使用 rewrite。这或许是 try_files 的一个 bug。

Magento sub category url at level 1

Although Google said it does not matter if you put pages at deep level, it would be quite nice to put all category pages at level 1. I have not found a way to achieve it in Magento.

I have a strong reason to put sub category url at level 1 besides of SEO – Sometime I need reorganise the category hierarchy. If moving category around changes its url, the site will produce 404 error if the visitor visiting the site via bookmark or search engine cached url.

Magento takes care of product pages very well. It asks you whether to use categories path for product URLs. However, Magento does not ask the same question for sub category pages. If a sub category is at level 3 from root category, its url will be sub-category-level-1/sub-category-level-2/sub-category-level-3. That is too long. If you can make sure each category (no matter which category it belongs to) url identifier identical, why Magento not simply use sub-category-level-3 as url?

What Makes A Good Web Program

我看问题可能有局限性,但我现在判断程序好坏的必要非充分条件之一是:这套程序能否充分利用Apache Url Rewrite。换句话说,如果是php程序,这套程序的前台页面是否由一个index.php来产生。

以这个条件来看,Zen Cart算好,Magento当然更好,osCommerce就不算好;Drupal / Joomla 都算好,WordPress 当然算是典范,Xoops 就不怎么样了。

也是因为这个原因,我放弃关注Xoops——痛苦地放弃,尽管曾经它是我的最爱,尽管它有某些功能很独到。

发现一个wordpress不够体贴的地方

熟悉以后才知道它/他/她的缺点,这就是为什么离婚总是发生在结婚后。

我在了解wordpress的过程遇到这么点小麻烦:custom permalink structure为/%post_id%/%postname%/(其实seo并非非得这么设置,但这个设置是我们价值£750每月的引擎优化专家推荐的,姑且采用)。

我事先知道这个blog所在的服务器目前没加载mod_rewrite,因为这不是我的独立服务器,所以我并不能想加载什么模块就可以加载的。但我暂时不想为了贪图mod_rewrite就把blog转移到另一个服务器,至少在这个blog正式上市之前不想。保持一个主服务器在美国,一个大副服务器在德国,以后再弄一个二副服务器在英国当地,或者把大副二副换一换,这是我理想中的格局,不把鸡蛋放一个篮子里嘛。

但我有个毛病,明知不可为而为之,就是想看看什么后果。结果我知道了:后果很严重。一旦修改了permalink,wordpress就自动生成一个.htaccess,不管服务器是否支持,也不管blog是否真的需要这个.htaccess。由于服务器没有加载mod_rewrite,所以发生500 server error。于是我删掉了.htaccess,然后在后台想把permalink改回Default,wordpress不够体贴的地方就暴露出来了:只要一提交permalink的值,不管这个新值是什么,wordpress就自动生成.htaccess,这样我的服务器马上就500,php肯定就中止执行了,数据库就无法更新了。这个鸡先生蛋、还是蛋先生鸡的问题,我最后是直接操纵数据库才解决的(wordpress的数据库结构还是挺清晰的,我没看什么资料,凭着直觉找到wp_options table,再找到permalink_structure,删掉option_value就可以了)。

说了一个wordpress的缺点,作为补偿,我再说一个我感觉到的体贴,总是在细致之处。当初安装wordpress,ftp原码以后,installation要求把wp-config-smaple.php改名为wp-config.php,虽然改名不算麻烦,我还嘀咕它为什么不直接替我做了这件事。最近一次升级才让我理解它的良苦用心——升级时只要一股脑ftp所有文件,不用担心设置文件的备份恢复等等。我以前一直都不太愿意升级,就是怕备份恢复这些琐事,所以wordpress新版本出了很久了,可能新版本的新版本都已经出了n多个了,我才折腾了一下。有了这次无痛升级的过程,我以后一定会升级得很勤快的。

题外话:wordpress的permalink基于url rewrite,要求服务器服务器是apache+mod_rewrite,适用性小。要是谁能开发一个plugin,基于404错误捕获做permalink,一定会在广大小空间业主群里有市场。不过我不会想着去做这件事,从基于url rewrite到基于404,技术上是种倒退。要向前看,不是向钱看。