我正在一个运行在共享Apache v2.2服务器上的网站上工作,因此所有配置都是通过.htaccess文件进行的,我想使用mod_rewrite以不太完全直接的方式将URL映射到文件系统.举个例子,让我们说我想做的是:
www.mysite.com/Alice到filesystem文件夹/public_html/Bobwww.mysite.com/Bob到filesystem文件夹/public_html/Alice现在,经过几个小时的工作,仔细设计规则集(真正的规则集,而不是Alice/Bob的规则集!)我将所有精心设计的重写规则放在/ public_html中的.htaccess文件中,然后对其进行测试... 500服务器错误!
我被一个记录良好的"陷阱"所困扰!在Apache中:当在.htaccess文件中使用mod_rewrite规则时,重新提交重写的URL 以进行另一轮处理(就像它是外部请求一样).这样就可以应用重写请求的目标文件夹中的任何规则,但它可能会导致网络服务器出现一些非常违反直觉的行为!
在上面的示例中,这意味着请求www.mysite.com/Alice/foo.html被重写/Bob/foo.html,然后作为请求重新提交(内部)到服务器www.mysite.com/Bob/foo.html.然后重新重新写入/Alice/foo.html并重新提交,这会导致重新重写/Bob/foo.html,等等; 随之而来的是无限循环...仅由服务器超时错误破坏.
RewriteRule中的[L]标志在单次通过规则集期间停止所有进一步的重写,但在重新提交重新提交到服务器之后不会停止重新应用整个规则集.根据文档,Apache v2.3.9 +(目前处于Beta版)包含一个[END]标志,可以精确地提供此功能.不幸的是,网络主机仍在使用Apache 2.2,他们拒绝我的礼貌请求升级到测试版!
我们需要的是一种解决方法,它提供与[END]标志类似的功能.我的第一个想法是我可以使用一个环境变量:在第一次重写过程中设置一个标志,告诉后续的传递不再进行重写.如果我调用我的标志变量'END',代码可能如下所示:
# Prevent further rewriting if 'END' is flagged
RewriteCond %{ENV:END} =1
RewriteRule .* - [L]
# Map /Alice to /Bob, and /Bob to /Alice, and flag 'END' when done
RewriteRule ^Alice(/.*)?$ Bob$1 [L,E=END:1]
RewriteRule ^Bob(/.*)?$ Alice$1 [L,E=END:1]
Run Code Online (Sandbox Code Playgroud)
不幸的是,这段代码不起作用:经过一些实验,我发现环境变量在重新提交重写的URL到服务器的过程中无法生存.这个Apache文档页面的最后一行表明环境变量 …
(最初这是作为方法提示发布的,我的答案包含在问题中.我现在将我的答案分成下面的"答案"部分).
更具体:
假设您正在向用户显示一组记录,分为固定大小的页面(例如,Google搜索的结果).如果只有几页,您可以在结果的末尾显示一个页面导航区域,如下所示:
[<<] [<] 1 2 3 4 5 6 7 8 9 10 11 12 13 [>] [>>]
但如果结果超过20或30页,这很快就变得不合适了.
有时你会看到这样的事情:
[<<] [<] ... 665 666 667 668 669 670 671 672 673 ... [>] [>>]
或这个:
[<<] [<] 1 2 3 ... 667 668 669 670 671 ... 845 846 847 [>] [>>]
但是在这两种情况下,导航到"......"部分中间的任何地方都会需要很多很多的mousclicks.有时会提供用于直接输入页码的输入框; 否则(假设我们在这里谈论一个网页),精明的用户可能会查看URL以查看他们是否可以直接编辑它.
最好的方法是使用分页显示,让用户只需几次鼠标点击就可以访问任何页面,而不会有太多荒谬的链接.
如何最好地实现?
navigation paging user-interface pagination large-data-volumes
这是一个"问自己一个问题并自己回答"的案例,我发帖是为了任何有同样问题的人的利益.
我在共享服务器上的.htaccess文件中调试mod_rewrite规则集时遇到了一些问题,我甚至无法访问Apache错误日志.我发现了一种调试它们的简洁方法,这是:
编写一个简短的脚本,只打印出它的查询字符串变量.例如在PHP中:
<?='<pre>',htmlentities(print_r($_GET,true)),'</pre>'?>
Run Code Online (Sandbox Code Playgroud)
是你所需要的全部.
假设您将此脚本命名为"show.php"并将其放在/ public_html中.然后在.htaccess文件中,确定您认为可能导致问题的规则集中的点,并插入此规则:
RewriteRule (.*) /show.php?url=$1 [END]
Run Code Online (Sandbox Code Playgroud)效果与在常规程序中插入PRINT语句相同.它会让你知道(a)你到达了规则集中的那一点,以及(b)当前重写的URL是什么.
它不像真正的调试工具那样闪存,但它完成了工作.
如果您使用的是Apache <2.3.9,则必须使用[L]而不是[END].在这种情况下,需要注意的是您的规则集不应该尝试将"/show.php"重写为其他任何内容.如果这是一个问题,您可以通过在顶部添加此规则来修复它:
RewriteRule ^show.php$ - [L]
Run Code Online (Sandbox Code Playgroud)
...只需记住在完成调试后将其删除!
假设我有一张表格mytable:
select * from mytable:
+------+------+------+
| a | b | c |
+------+------+------+
| 1 | 1 | a |
| 1 | 2 | b |
+------+------+------+
我想用功能将b和c列分组group_concat:
select a, group_concat(b), group_concat(c) from mytable group by a
+------+-----------------+-----------------+
| a | group_concat(b) | group_concat(c) |
+------+-----------------+-----------------+
| 1 | 1,2 | a,b |
+------+-----------------+-----------------+
我的问题是,执行mysql的保证,那group_concat将永远以同样的顺序,我不会得到这样的结果,1,2在第二列和B,A在第三列?
.htaccess ×2
mod-rewrite ×2
debugging ×1
group-by ×1
group-concat ×1
loops ×1
mysql ×1
navigation ×1
pagination ×1
paging ×1
redirect ×1
sql ×1