1. 程式人生 > >Gracefully handling application exceptions in a Tornado application

Gracefully handling application exceptions in a Tornado application

之前在DigitalOcean 的主機上用wordpress架了一個web site站臺,只使用了 port 80, 後來在 443 port 架了 tornado, 滿神奇的,tornado 可以直接使用 letsencrypt 的憑證檔案。

後來發現 googlebot 會來parse 443 port 裡的資料。所以我希望 404 錯誤的資料就從80 port 裡重新取得一次,丟給Google.

取得 ssl 憑證

照上面教學的指令下,只用一行就可以產生憑證。知道網站的根目錄用這行(指令1號):

letsencrypt certonly --webroot -w /var/www/example -d example.com

如果你完全沒有網站,可以使用這行(指令2號):

letsencrypt certonly --standalone -d example.com -d www.example.com

指令1號,letsencrypt 會放東西在 webroot 目錄裡,然後letsencrypt用 80 port 連回我們伺服器進去測試。

指令2號,會自動產生一個 80 port 的 service,然後letsencrypt用 80 port 連回我們伺服器進去測試。

這2個指令,都會因此去使用 443 port,實際上原理不需要了解太多,certbot 寫的滿聰明的,會在畫面上有提醒。產生完,手動測一下 renew,沒問題的把把 renew 指令放進排程裡。

letsencrypt renew --dry-run --agree-tos

成功後就會在ubuntu的/etc/letsencrypt/archive/ 下面看到憑證了。

在 80和443 port 都已經被其他程式使用中的請況下,需要更進階的設定,參考看看這一篇:

例如:

letsencrypt certonly --standalone -d example.com --tls-sni-01-port 445 --http-01-port 82

修改Tornado的 ssl_options

tornado改程式,須追加此兩個檔案的路徑在ssl_options下面,並注意檔案許可權要能被讀。

http_server = tornado.httpserver.HTTPServer(Application(),
ssl_options={
“certfile”: “cert.pem”, #自行填好路徑
“keyfile”: “privkey.pem”, #自行填好路徑
})

要使用下面的這組設定值來完成自動轉發:

  • default_handler_class and default_handler_args: This handler will be used if no other match is found; use this to implement custom 404 pages (new in Tornado 3.2).

範例寫法:

import tornado.web


class BaseHandler(tornado.web.RequestHandler):
    """
    Base handler gonna to be used instead of RequestHandler
    """
    def write_error(self, status_code, **kwargs):
        if status_code in [403, 404, 500, 503]:
            self.write('Error %s' % status_code)
        else:
            self.write('BOOM!')


class ErrorHandler(tornado.web.ErrorHandler, BaseHandler):
    """
    Default handler gonna to be used in case of 404 error
    """
    pass


class MainHandler(BaseHandler):
    """
    Main handler
    """
    def get(self):
        self.write('Hello world!')
  1. Settings. We need to define default_handler_class and default_handler_args as well
settings = {
    'default_handler_class': ErrorHandler,
    'default_handler_args': dict(status_code=404)
}
  1. Application.
application = tornado.web.Application([
    (r"/", MainHandler)
], **settings)

as result. all errors except 404 gonna be handled by BaseHandler. 404 – ErrorHandler. that’s it