Apache2 + RewriteMap + Python -- 返回'NULL'时,Apache挂起

2 投票
2 回答
3183 浏览
提问于 2025-04-15 15:08

[已解决:请见下方解决方案]

我在写一个 RewriteMap 程序时遇到了问题(使用Python)。我有一个 RewriteMap 指令,它指向一个Python脚本,这个脚本用来判断请求的URL是否需要重定向到其他地方。

当这个脚本输出一个以换行符结束的字符串时,Apache会根据这个输出进行重定向。然而,当脚本输出 NULL(没有换行符)时,Apache就会卡住,后续的HTTP请求基本上就被忽略了。

错误日志没有显示任何错误。重写日志在成功时只显示 pass throughredirect,但当脚本返回 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 个回答

4

到目前为止,我想到的最佳解决方案是让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

6

你需要返回一个换行符,而不是'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)。但考虑到你的问题,这看起来是个合适的解决方案。

撰写回答