跟 Flask 相比, tornado 似乎討論的文章比較少, 但Max最喜歡使用的 web server 是 tornado, 今天來介紹 tornado 如何與 Flask 一樣, 掛載靜態檔案.
Flash 的使用方法, 真的很直覺, 程式碼也超短:
https://stackoverflow.max-everyday.com/2023/02/flask-web-server-static-file/
Tornado 對靜態檔案的說明:
https://www.tornadoweb.org/en/stable/web.html#tornado.web.StaticFileHandler
使用下面的範例, 就可以存取到靜態檔案:
import asyncio
import tornado
from tornado.web import Application
from tornado.web import StaticFileHandler
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
def make_app():
return Application([
(r"/", MainHandler),
(r"/content/(.*)", StaticFileHandler, {"path": "./content"}),
])
async def main():
app = make_app()
app.listen(8888)
await asyncio.Event().wait()
if __name__ == "__main__":
asyncio.run(main())
說明: ./content/ 輸出網頁的 /content/
使用的執行範例:
http://127.0.0.1:8888/content/static.py
有一個奇怪的坑是, 如果你在 create Application(routes, **app_settings) object 時, 所帶入的 app_settings = dict( ) 中間使用 static_path, 例如:
app_settings = dict(
template_path=os.path.join(os.path.dirname(__file__), "templates"),
static_path=os.path.join(os.path.dirname(__file__), "static"),
這時候, 又在 routes 裡設了 static, 例如:
handlers = [
(r'/', MainHandler),
(r'/static/(.*)', StaticFileHandler, {'path': "static"}),
]
2邊就會衝突, 原本應該正常顯示的靜態檔案都會成錯誤訊息:
Traceback (most recent call last):
File "D:\Programs\Python\Python39-32\lib\site-packages\tornado\web.py", line 1713, in _execute
result = await result
File "D:\Programs\Python\Python39-32\lib\site-packages\tornado\web.py", line 2611, in get
self.absolute_path = self.validate_absolute_path(self.root, absolute_path)
File "D:\Programs\Python\Python39-32\lib\site-packages\tornado\web.py", line 2813, in validate_absolute_path
raise HTTPError(404)
tornado.web.HTTPError: HTTP 404: Not Found
根目錄以下到 /static/目錄下取檔案, 並針對 404 不存在的檔案做客製化:
class MyStaticFileHandler(StaticFileHandler):
def write_error(self, status_code, *args, **kwargs):
my_404_page = os.path.join(options.app_root, 'template/error_404.html')
self.set_status(status_code)
if status_code in [404]:
self.render(my_404_page)
else:
self.write("Error: %d" % status_code)
handlers = [
(r'/', 'app.controller.HomeHandler'),
(r'/(.*)', MyStaticFileHandler, {'path': os.path.join(app_root, 'static/')}),
]