Apache2 + RewriteMap + Python -- 返回'NULL'时,Apache挂起
[已解决:请见下方解决方案]
我在写一个 RewriteMap
程序时遇到了问题(使用Python)。我有一个 RewriteMap
指令,它指向一个Python脚本,这个脚本用来判断请求的URL是否需要重定向到其他地方。
当这个脚本输出一个以换行符结束的字符串时,Apache会根据这个输出进行重定向。然而,当脚本输出 NULL
(没有换行符)时,Apache就会卡住,后续的HTTP请求基本上就被忽略了。
错误日志没有显示任何错误。重写日志在成功时只显示 pass through
和 redirect
,但当脚本返回 NULL
时,只显示 pass through
。后续的请求也只显示 pass through
。
另外,把 stdout
替换成 os.fdopen(sys.stdout.fileno(), 'w', 0)
来设置缓冲区长度为零也没有帮助。
任何帮助都将非常感激。提前谢谢你。
/etc/apache2/httpd.conf
[...]
RewriteLock /tmp/apache_rewrite.lock
/etc/apache2/sites-available/default
<VirtualHost *:80>
[...]
RewriteEngine on
RewriteLogLevel 1
RewriteLog /var/www/logs/rewrite.log
RewriteMap remap prg:/var/www/remap.py
[...]
</VirtualHost>
/var/www/webroot/.htaccess
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*_.*) /${remap:$1} [R=301]
/var/www/remap.py
#!/usr/bin/python
import sys
def getRedirect(str):
new_url = None
# if url needs to be redirected, put this value in new_url
# otherwise new_url remains None
return new_url
while True:
request = sys.stdin.readline().strip()
response = getRedirect(request)
if response:
sys.stdout.write(response + '\n')
else:
sys.stdout.write('NULL')
sys.stdout.flush()
2 个回答
到目前为止,我想到的最佳解决方案是让RewriteMap脚本返回新的网址,或者如果不需要重定向就返回'__NULL__\n'
,然后把这个值存储在一个环境变量中。接着,检查这个环境变量是否是!__NULL__
,如果不是,就进行重定向。下面是.htaccess
文件的内容。
另外,如果有人打算做类似的事情,在我的Python脚本中,我把很多代码放在了try/except块里,这样可以防止脚本崩溃(在我的情况下,是因为文件或数据库读取失败),从而避免后续的查询被忽略。
/var/www/webroot/.htaccess
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ - [E=REMAP_RESULT:${remap:$1},NS]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{ENV:REMAP_RESULT} !^__NULL__$
RewriteRule ^(.+)$ /%{ENV:REMAP_RESULT} [R=301,L]
/var/www/remap.py
#!/usr/bin/python
import sys
def getRedirect(str):
try: # to prevent the script from dying on any errors
new_url = str
# if url needs to be redirected, put this value in new_url
# otherwise new_url remains None
if new_url == str: new_url = '__NULL__'
return new_url
except:
return '__NULL__'
while True:
request = sys.stdin.readline().strip()
response = getRedirect(request)
sys.stdout.write(response + '\n')
sys.stdout.flush()
Vinko,你真的帮我解决了这个问题。如果我对stackoverflow
更熟悉,你肯定会收到我的^
。谢谢你。
我希望这篇帖子能帮助到将来遇到类似问题的人。
祝好,
Andrew
你需要返回一个换行符,而不是'NULL'。
Apache会等待一个换行符来判断要重写的URL在哪里结束。如果你的脚本没有发送换行符,Apache就会一直等待下去。
所以只需把 return ('NULL')
改成 return ('NULL\n')
,这样就会重定向到根目录(/)。如果你不想这样做,可以让程序在映射中没有匹配时返回你想要的URL。
如果你希望在没有匹配时不进行重定向,我会这样做:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond (${remap:$1}) !NULL
RewriteRule (.*_.*) /%1 [R=301]
在RewriteCond中使用一个匹配(当然,这也适用于NULL)。但考虑到你的问题,这看起来是个合适的解决方案。