Flask で HTML ではないデータを返送する場合、通常は HTML 応答に Content-Type ヘッダーを設定することになる。そのためには Response
オブジェクトの mimetype
プロパティや content_type
プロパティに値を設定すれば良いのだけれど、これまでどちらに値を設定しても同じだと思っていた。が、実は動作の違いがあることに気が付いたので、調べてみた。
Flask もとい Werkzeug の Response
オブジェクトでは、content_type
プロパティが Content-Type ヘッダーの値そのものであるのに対して、mimetype
プロパティは「Content-Type ヘッダー値のうち MIME-Type の部分」を表している。つまり Content-Type が text/html; charset=utf-8
であれば、mimetype
プロパティは text/html
の部分に対応している。
これらのプロパティを読み出す場合は上記の理解だけで何ら問題無いけれど、値を「設定する」場合は少しだけ注意が必要だ。というのも content_type
プロパティはヘッダー値の全体が置き換わるのに対し、mimetype
プロパティに値を設定すると MIME Type 部分だけが置き換わるわけではなく、「全体を書き換えつつ、ただし設定した値が text/***
だった場合は charset
パラメータが自動的に追加される」という動きをする:
Special note for mimetype and content_type: For most mime types mimetype and content_type work the same, the difference affects only ‘text’ mimetypes. If the mimetype passed with mimetype is a mimetype starting with text/, the charset parameter of the response object is appended to it. In contrast the content_type parameter is always added as header unmodified.
—Request / Response Objects — Werkzeug Documentation (0.15.x)
試してみると、確かにそのような動作になっているね:
>>> import flask >>> resp = flask.Response("Hello") >>> resp.headers Headers([('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', '5')]) >>> >>> # mimetypeへの設定時はcharsetパラメータが自動補完される >>> resp.mimetype = "text/css" >>> resp.headers Headers([('Content-Type', 'text/css; charset=utf-8'), ('Content-Length', '5')]) >>> >>> # "text/"でなければ補完されない >>> resp.mimetype = "application/json" >>> resp.headers Headers([('Content-Type', 'application/json'), ('Content-Length', '5')]) >>> >>> # content_typeプロパティの場合は問答無用で値全体が置き換わる >>> resp.content_type = "text/css" >>> resp.headers Headers([('Content-Type', 'text/css'), ('Content-Length', '5')]) >>> >>> # charset付きの値を設定すれば同じことができる >>> resp.content_type = "text/css; charset=utf-8" >>> resp.headers Headers([('Content-Type', 'text/css; charset=utf-8'), ('Content-Length', '5')])
どちらが良いかは好みの問題という気はする。ただ、違いがあることは記憶にとどめておいた方が良さそうだね。