多个应用静态文件路径的处理

问题情景

在一个服务器上的两个不同端口下都有Python Tornadoweb的应用在运行,这个时候静态文件(static files)就会变得非常难处理。现在假设我们有两个应用A和B,A应用在8123端口运行;

1
2
3
4
5
6
if __name__=="__main__":
app = Application()
http_server = tornado.httpserver.HTTPServer(app)
print('Server has started')
http_server.listen(8123)
tornado.ioloop.IOLoop.instance().start()

B应用在8321端口运行;

1
2
3
4
5
6
if __name__=="__main__":
app = Application()
http_server = tornado.httpserver.HTTPServer(app)
print('Server has started')
http_server.listen(8321)
tornado.ioloop.IOLoop.instance().start()

虚拟主机 (Virtual Host)

再假设为了安全与美观,我们使用VirtualHost做了端口代理,让用户访问地址中不会出现端口。

1
2
3
4
5
6
7
8
9
<VirtualHost *:443>
ProxyPreserveHost On

ProxyPass /applicationA http://0.0.0.0:8123/applicationA
ProxyPassReverse /applicationA http://0.0.0.0:8123/applicationA

ProxyPass /applicationB http://0.0.0.0:8321/applicationB
ProxyPassReverse /applicationB http://0.0.0.0:8321/applicationB
</VirtualHost>

此时用户可以通过 https://<domain>/applicationAhttps://<domain>/applicationB 来访问两个应用。

多个静态文件路径

一般情况下不同的应用开发会使用不同的路径来存放静态文件(static path),Apache也是允许多个路径存在的,可以使用Directory将多个文件路径添加到设置中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<VirtualHost *:443>
ProxyPreserveHost On

<Directory /path/to/applicationA>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
ProxyPass /applicationA http://0.0.0.0:8123/applicationA
ProxyPassReverse /applicationA http://0.0.0.0:8123/applicationA

<Directory /path/to/applicationB>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
ProxyPass /applicationB http://0.0.0.0:8321/applicationB
ProxyPassReverse /applicationB http://0.0.0.0:8321/applicationB
</VirtualHost>

但是,添加多个路径后,服务器不知道什么时候应该读取A的静态文件,什么时候该读取B的,此时会导致静态文件读取错误。

使用static_path + static_url_prefix + Alias可以很好的解决问题:

首先,在Tornadoweb使用static_path + static_url_prefix,给A应用的静态文件地址一个特定的前缀;

1
2
"static_path": os.path.join(os.path.dirname(__file__), "/path/to/applicationA"),
"static_url_prefix": "/resourcesA/",

再给B应用的静态文件地址一个特定的前缀;

1
2
"static_path": os.path.join(os.path.dirname(__file__), "/path/to/applicationB"),
"static_url_prefix": "/resourcesB/",

(使用过Tornadoweb应该知道这里static_path的默认值是static)

此时在端口运行时会发现所有的静态文件路径有特定前缀,以A应用为例就是:

1
https://<domain>:8123/resourcesA/templates/css/applicationA.css

最后使用Apache的Alias对两个静态文件路径进行区别即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<VirtualHost *:443>
ProxyPreserveHost On

Alias /resourcesA /path/to/applicationA
<Directory /path/to/applicationA>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
ProxyPass /applicationA http://0.0.0.0:8123/applicationA
ProxyPassReverse /applicationA http://0.0.0.0:8123/applicationA

Alias /resourceB /path/to/applicationB
<Directory /path/to/applicationB>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
ProxyPass /applicationB http://0.0.0.0:8321/applicationB
ProxyPassReverse /applicationB http://0.0.0.0:8321/applicationB
</VirtualHost>

此时,由于在Tornadoweb里两个应用的静态文件路径前缀不同,服务器在读取时就不会混淆。