bottle + CGI 始终匹配/路线

问题描述 投票:0回答:2

在 CGI 环境中部署时,我无法让 bottle 匹配除“/”之外的任何其他路由。 (不幸的是,我受困于托管服务提供商,不提供 FastCGI 或 WSGI)。

Bottle 位于一个子目录中

lib
- 我已经从 bottle-0.12.18.tar.gz 那里删除了 bottle.py。

Python 是 3.5.3(提供商)或 3.8.2(本地主机)

我在

.htaccess

中有以下内容
Options +ExecCGI
AddHandler cgi-script .py

Options -Indexes

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteRule ^static\/ - [L]  
  RewriteRule .* application.py [L]
</IfModule>

和以下

application.py

#!/usr/bin/python3

#setup lib path
import os
import os.path
import sys
if 'SCRIPT_NAME' in os.environ:
    MY_DIR = os.path.dirname(os.path.realpath(os.environ['SCRIPT_FILENAME']))
else:
    MY_DIR = os.environ['PWD']    
sys.path.append(os.path.join(MY_DIR,'lib'))


from bottle import Bottle

app = Bottle()

@app.route('/test')
def test():
    return '<b>matched @app.route("/test") - Testing: One, Two</b>!'

@app.route('/')
def index():
    r = ""
    for p in os.environ.keys():
        r += "{0} : {1}\n".format(p,os.environ[p])
    return '<b>matched @app.route("/")</b>\n<pre>'+r+'</pre>'

app.run(server='cgi')

总是返回

index()
的输出,无论我请求什么URL。

从输出

matched @app.route("/")

APP_ENGINE : phpcgi
APP_ENGINE_VERSION : 7.3
AUTH_TYPE : Basic
CFG_CLUSTER : cluster003
DOCUMENT_ROOT : /home/somethinguxiz/www-dev
ENVIRONMENT : production
GATEWAY_INTERFACE : CGI/1.1
HOME : /homez.907/somethinguxiz
HTTP_ACCEPT_ENCODING : gzip, deflate, br
HTTP_ACCEPT_LANGUAGE : en,de-DE;q=0.7,de;q=0.3
HTTP_ACCEPT : text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
HTTP_DNT : 1
HTTP_FORWARDED : for=51.xxx.xxx.xxx; proto=https; host=dev.something.else
HTTP_HOST : dev.something.else
HTTP_REMOTE_IP : 90.xxx.xxx.xxx
HTTPS : on
HTTP_UPGRADE_INSECURE_REQUESTS : 1
HTTP_USER_AGENT : Mozilla/5.0 (X11; Linux x86_64; rv:74.0) Gecko/20100101 Firefox/74.0
HTTP_X_FORWARDED_FOR : 90.xxx.xxx.xxx
HTTP_X_FORWARDED_PORT : 443
HTTP_X_FORWARDED_PROTO : https
HTTP_X_PREDICTOR : 1
HTTP_X_REMOTE_IP : 51.xxx.xxx.xxx
HTTP_X_REMOTE_PORT : 64440
HTTP_X_REMOTE_PROTO : https
PATH : /usr/local/bin:/usr/bin:/bin
PHP_VER : 5_TEST
PWD : /homez.907/somethinguxiz/www-dev
QUERY_STRING : 
REDIRECT_STATUS : 200
REDIRECT_URL : /test
REGISTER_GLOBALS : 0
REMOTE_ADDR : 90.xxx.xxx.xxx
REMOTE_PORT : 17926
REMOTE_USER : csomething
REQUEST_METHOD : GET
REQUEST_URI : /test
SCRIPT_FILENAME : /home/somethinguxiz/www-dev/application.py
SCRIPT_NAME : /application.py
SCRIPT_URI : https://dev.something.else:443/test
SCRIPT_URL : /test
SERVER_ADDR : 51.xxx.xxx.xxx
SERVER_ADMIN : [email protected]
SERVER_NAME : dev.something.else
SERVER_PORT : 443
SERVER_PROTOCOL : HTTP/1.1
SERVER_SIGNATURE : 
SERVER_SOFTWARE : Apache
UID : somethinguxiz

即脚本确实看到了

REQUEST_URI
但它没有触发
test()
但是
index()
!?

任何想法,指示?

编辑: 除非它在某处被删除,

PATH_INFO
在上面的列表中丢失了,尽管如果我正确理解 CGI 规范它应该在那里。这也是 bottle 在其 match() 方法中使用的。如果不存在,它会回落到
/
(这说明总是
index()
被调用。

编辑:将解决方案文本移动到答案

python apache routes cgi bottle
2个回答
0
投票

PATH_INFO
仅在路径超出 cgi 脚本时设置。虽然我的初衷是让它不可见,但我已经安心地在这里使用了一个应用程序名称。另外,与
[L]
相比,重写规则中有
[END]
是有区别的。

因此我解决了以下

.htaccess


Options +ExecCGI                                                                                                                     
AddHandler cgi-script .py                                                                                                            
AcceptPathInfo on                                                                                                                    

Options -Indexes                                                                                                                     

<IfModule mod_rewrite.c>                                                                                                             
    RewriteEngine On                                                                                                                 
    RewriteOptions IgnoreInherit                                                                                                     
    RewriteBase /                                                                                                              
    RewriteRule ^demo\/(static\/.*)$ $1 [END]                                                                                        
    RewriteRule ^demo(/.*)$ application.py$1 [END]                                                                                   
    RewriteRule ^demo$ application.py [END]                                                                                           
    RewriteRule !^demo$ demo [R,END]                                                                                                  
</IfModule>                                                                                                                          

它允许在应用程序逻辑处于

application.py
时从 httpd 提供静态内容 - 隐藏为
demo
。其他任何内容都会重定向到前门。

申请时间为

.../demo
, 应用程序中的页面位于
.../demo/path/to/page
,并且 httpd 提供的资源位于
.../demo/static/path/to/ressource


0
投票

我也有这个问题,并找到了一个解决方案,可以让我完全消除脚本本身的任何路径残留。 CGI 脚本目录中 .htaccess 文件中的以下 Apache Rewrite 指令起到了作用:

<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteBase /

  RewriteRule ^$ script.py                # (1)
  RewriteCond %{REQUEST_FILENAME} !-f     # (2)
  RewriteCond %{REQUEST_FILENAME} !-d     # (3)
  RewriteRule ^(.*)$ script.py/$1 [QSA,L] # (4)
</IfModule>

编号行的解释:

  1. 第一个 RewriteRule 将任何 index 请求(例如 https://www.example.com 带或不带尾部斜线)直接发送到脚本。这满足了我一半的需求:让“前门”也由我的脚本处理。 如果您有静态索引页面,请忽略此规则。
  2. 此条件处理静态文件:如果它已存在于请求位置,则跳过下一次重写。由于下一个规则是脚本如何看到非索引请求,这使得 Apache 直接为它提供服务而不是将它发送到脚本。 如果您没有要提供的静态文件,或者希望应用程序自己的逻辑提供静态文件,请忽略此条件。
  3. 与 (2) 相同,但用于目录。
  4. 解决方案的另一半。这将重写之前规则尚未提供的任何请求:像
    /<non-empty-request>
    这样的任何东西都会像
    /script.py/<non-empty-request>
    一样运行。

因此,第一行的规则将

https://www.example.com
发送到我的脚本让它的
@app.route('/')
处理程序正确地完成它的工作,而不管静态索引文件如何,第四行的规则确保所有其他非静态文件的请求都正确地提供给脚本,并由所有其他已注册的路由处理程序处理。

作为旁注,

RewriteBase /
不是绝对必要的,但我喜欢将默认设置明确化。请参阅这个关于 RewriteBase 在 .htaccess 中如何工作 的答案以彻底分解
RewriteBase
及其用途。

© www.soinside.com 2019 - 2024. All rights reserved.