可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I want to know if there is a better way to handle my index.html file with Tornado.
I use StaticFileHandler for all the request,and use a specific MainHandler to handle my main request. If I only use StaticFileHandler I got a 403: Forbidden error
GET http://localhost:9000/
WARNING:root:403 GET / (127.0.0.1): is not a file
here how I doing now:
import os
import tornado.ioloop
import tornado.web
from tornado import web
__author__ = 'gvincent'
root = os.path.dirname(__file__)
port = 9999
class MainHandler(tornado.web.RequestHandler):
def get(self):
try:
with open(os.path.join(root, 'index.html')) as f:
self.write(f.read())
except IOError as e:
self.write("404: Not Found")
application = tornado.web.Application([
(r"/", MainHandler),
(r"/(.*)", web.StaticFileHandler, dict(path=root)),
])
if __name__ == '__main__':
application.listen(port)
tornado.ioloop.IOLoop.instance().start()
回答1:
Turns out that Tornado's StaticFileHandler already includes default filename functionality.
Feature was added in Tornado release 1.2.0:
https://github.com/tornadoweb/tornado/commit/638a151d96d681d3bdd6ba5ce5dcf2bd1447959c
To specify a default file name you need to set the "default_filename" parameter as part of the WebStaticFileHandler initialization.
Updating your example:
import os
import tornado.ioloop
import tornado.web
root = os.path.dirname(__file__)
port = 9999
application = tornado.web.Application([
(r"/(.*)", tornado.web.StaticFileHandler, {"path": root, "default_filename": "index.html"})
])
if __name__ == '__main__':
application.listen(port)
tornado.ioloop.IOLoop.instance().start()
This handles root requests:
sub-directory requests:
/tests/
-> /tests/index.html
and appears to correctly handle redirects for directories, which is nice:
/tests
-> /tests/index.html
回答2:
Thanks to the previous answer, here is the solution I prefer:
import Settings
import tornado.web
import tornado.httpserver
class Application(tornado.web.Application):
def __init__(self):
handlers = [
(r"/", MainHandler)
]
settings = {
"template_path": Settings.TEMPLATE_PATH,
"static_path": Settings.STATIC_PATH,
}
tornado.web.Application.__init__(self, handlers, **settings)
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render("index.html")
def main():
applicaton = Application()
http_server = tornado.httpserver.HTTPServer(applicaton)
http_server.listen(9999)
tornado.ioloop.IOLoop.instance().start()
if __name__ == "__main__":
main()
And Settings.py
import os
dirname = os.path.dirname(__file__)
STATIC_PATH = os.path.join(dirname, 'static')
TEMPLATE_PATH = os.path.join(dirname, 'templates')
回答3:
Use this code instead
class IndexDotHTMLAwareStaticFileHandler(tornado.web.StaticFileHandler):
def parse_url_path(self, url_path):
if not url_path or url_path.endswith('/'):
url_path += 'index.html'
return super(IndexDotHTMLAwareStaticFileHandler, self).parse_url_path(url_path)
now use that class instead of vanilla StaticFileHandler in your Application... job's done!
回答4:
There is no need to explicitly add a StaticFileHandler
; just specify the static_path and it will serve those pages.
You are correct that you need a MainHandler, as for some reason Tornado will not serve the index.html
file, even if you append the filename to the URL.
In that case, this slight modification to your code should work for you:
import os
import tornado.ioloop
import tornado.web
from tornado import web
__author__ = 'gvincent'
root = os.path.dirname(__file__)
port = 9999
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render("index.html")
application = tornado.web.Application([
(r"/", MainHandler),
], template_path=root,
static_path=root)
if __name__ == '__main__':
application.listen(port)
tornado.ioloop.IOLoop.instance().start()
回答5:
I have been trying this. Don't use render it has additional overhead of parsing templates and gives error on template type strings in static html. I found this is the simplest way. Tornado is looking for a capturing parenthesis in regex , just give it an empty capturing group.
import os
import tornado.ioloop
import tornado.web
root = os.path.dirname(__file__)
port = 9999
application = tornado.web.Application([
(r"/()", tornado.web.StaticFileHandler, {"path": root, "default_filename": "index.html"})
])
This has effect of resolving / to index.html and also avoid unwanted resolves like /views.html to static_dir/views.html
回答6:
This worked for me From the tornado docs:
To serve a file like index.html
automatically when a directory is requested, set static_handler_args=dict(default_filename="index.html")
in your application settings, or add default_filename
as an initializer argument for your StaticFileHandler
.