is there a better way to handle index.html with To

2019-03-09 21:06发布


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()

6条回答
2楼-- · 2019-03-09 21:47

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楼-- · 2019-03-09 21:51

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

查看更多
孤傲高冷的网名
4楼-- · 2019-03-09 21:54

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.

查看更多
冷血范
5楼-- · 2019-03-09 21:59

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()
查看更多
虎瘦雄心在
6楼-- · 2019-03-09 22:03

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:

  • / -> /index.html

sub-directory requests:

  • /tests/ -> /tests/index.html

and appears to correctly handle redirects for directories, which is nice:

  • /tests -> /tests/index.html
查看更多
叼着烟拽天下
7楼-- · 2019-03-09 22:03

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!

查看更多
登录 后发表回答