Flaskで静的ファイルの格納ディレクトリとURLを変更する

## 1. はじめに
今回はflaskで静的ファイルにアクセスするためのURLのパスと、格納ディレクトリの変更方法について説明します。また、通常REST APIでは静的ファイルは不要なため、これを無効にする方法についても説明したいと思います。

### 1.1. 検証環境
* Python 2.7.13
* Flask 0.12.2

## 2. 格納ディレクトリは`static_folder`で変更
flaskで静的ファイルを格納するディレクトリは`static_folder`で変更することができます。
デフォルトの設定は`static`ディレクトリです。

## 2.1. ソースコード 
```python:dir_change_app.py
# -*- coding: utf-8 -*-
import os
from flask import Flask

# flask
# app = Flask(__name__)
# 相対パスで指定
app = Flask(__name__, static_folder='resources')
# 絶対パスで指定（ディレクトリは/）
# app = Flask(__name__, static_folder='C:/tmp/www')
# 絶対パスで指定（ディレクトリは\\）
# app = Flask(__name__, static_folder='C:\\tmp\\www')

# main
if __name__ == "__main__":
    # Flaskのマッピング情報を表示
    print app.url_map
    app.run(host=os.getenv("APP_ADDRESS", 'localhost'), \
    port=os.getenv("APP_PORT", 3000))
```

**flaskの`url_map`で現在のマッピング情報を確認することができます。**

## 2.2. 動作確認 
```console:デフォルトのまま、指定なし
C:\demo>python dir_change_app.py
Map([<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>])
 * Running on http://localhost:3000/ (Press CTRL+C to quit)
127.0.0.1 - - [19/Aug/2017 14:17:28] "GET /static/memo.txt HTTP/1.1" 200 -
```
デフォルトでは、カレントディレクトリに`static`ディレクトリがある前提で起動します。ですので、`static`ディレクトリを作成して`memo.txt`を格納した後、Webブラウザで`http://localhost:3000/static/memo.txt`にアクセスすると`memo.txt`が表示されます。

```console:相対パスで指定
C:\demo>python dir_change_app.py
Map([<Rule '/resources/<filename>' (HEAD, OPTIONS, GET) -> static>])
 * Running on http://localhost:3000/ (Press CTRL+C to quit)
127.0.0.1 - - [19/Aug/2017 14:03:36] "GET /resources/demo.js HTTP/1.1" 200 -
```
相対パスで`resources`ディレクトリを指定すると、Webブラウザからは`http://localhost:3000/resources/demo.js`のようにアクセスすることになります。

```console:絶対パスで指定
C:\demo>python dir_change_app.py
Map([<Rule '/www/<filename>' (HEAD, OPTIONS, GET) -> static>])
 * Running on http://localhost:3000/ (Press CTRL+C to quit)
127.0.0.1 - - [19/Aug/2017 14:04:57] "GET /www/demo.js HTTP/1.1" 200 -
```
絶対パスでも指定することができます。Windowsの場合はディレクトリの区切りは`/`か`\\`で記述します。
絶対パスの場合、パスの最後尾のディレクトリ名がURLのパス名となります。デモの`static_folder='C:/tmp/www'`の場合は`/www`になります。
URLを変更する方法がこの後の説明になります。

## 3. アクセスするURLは`static_url_path`で変更
flaskで静的ファイルにアクセスするURLは`static_url_path`で変更することができます。
デフォルトの設定は`static_folder`で指定したディレクトリ名と同じになります。

### 3.1. ソースコード
```python:url_change_app.py
# -*- coding: utf-8 -*-
import os
from flask import Flask

# flask
app = Flask(__name__)
# URLのパスを指定
app = Flask(__name__, static_url_path='/js')
# URLのパスに複数の区切りを利用
# app = Flask(__name__, static_url_path='/h/o/g/e')
# URLのパスに何も指定したくない場合は空文字を指定
# app = Flask(__name__, static_url_path='')

# main
if __name__ == "__main__":
    # Flaskのマッピング情報を表示
    print app.url_map
    app.run(host=os.getenv("APP_ADDRESS", 'localhost'), \
    port=os.getenv("APP_PORT", 3000))
```
ここでは`static_folder`で格納ディレクトリを指定していないため、デフォルトの通り、カレントディレクトリの`static`ディレクトリに静的ファイルを格納します。

**`static_url_path`で指定する値は必ず`/`で始まる必要があるので注意してください。**

### 3.2. 動作確認
```console:普通にURLのパスを指定
C:\demo>python url_change_app.py
Map([<Rule '/js/<filename>' (HEAD, OPTIONS, GET) -> static>])
 * Running on http://localhost:3000/ (Press CTRL+C to quit)
127.0.0.1 - - [19/Aug/2017 14:57:08] "GET /js/demo.js HTTP/1.1" 200 -
```
格納ディレクトリは`static`ですが、`/js/demo.js`でアクセスできるようになります。

```console:URLのパスに複数の区切りを指定
C:\demo>python url_change_app.py
Map([<Rule '/h/o/g/e/<filename>' (HEAD, OPTIONS, GET) -> static>])
 * Running on http://localhost:3000/ (Press CTRL+C to quit)
127.0.0.1 - - [19/Aug/2017 14:57:51] "GET /h/o/g/e/demo.js HTTP/1.1" 200 -
```
URLでアクセスする際に利用するパスのため、複数の区切りを指定しても問題なく`demo.js`にアクセスできます。

```console:パスに何も指定しない場合
C:\demo>python url_change_app.py
Map([<Rule '/<filename>' (HEAD, OPTIONS, GET) -> static>])
 * Running on http://localhost:3000/ (Press CTRL+C to quit)
127.0.0.1 - - [19/Aug/2017 14:58:39] "GET /demo.js HTTP/1.1" 200 -
```
`/demo.js`のように不要なパスを指定することなく、格納ディレクトリ内のファイル名を指定するだけでアクセスできます。

## 4. 無効にするには`static_folder=None`を設定
### 4.1. ソースコード
```python:no_static_app.py
# -*- coding: utf-8 -*-
import os
from flask import Flask

# flask
# 静的ファイルの機能は無効
app = Flask(__name__, static_folder=None)

# main
if __name__ == "__main__":
    # Flaskのマッピング情報を表示
    print app.url_map
    app.run(host=os.getenv("APP_ADDRESS", 'localhost'), \
    port=os.getenv("APP_PORT", 3000))
```

### 4.2. 動作確認
```console:静的ファイルの機能は無効
C:\demo>python no_static_app.py
Map([])
 * Running on http://localhost:3000/ (Press CTRL+C to quit)
```
**マッピング情報を見ると何も設定されておらず、静的ファイルの機能が無効になっていることが分かるかと思います。**

## 5. さいごに
今回はflaskにおける静的ファイルの格納ディレクトリと、静的ファイルにアクセスするURLの変更方法について説明しました。

[Pythonでマイクロサービス（概要編）](http://qiita.com/5zm/items/d5375a4ad95fd67b8960)のとおりマイクロサービス（REST API）を作成するのが目的のため、本来、静的ファイルの機能は不要なのですが、マッピング情報を見て自動でこの機能が有効になっていることが分かりました。

自分と同じく気付いていない人もいるのではと思い、今回記事としてまとめてみました。

flask以外のライブラリでもそうですが、セキュリティ的な観点から、デフォルトで有効になっている機能についてはしっかりと調査し、内容を把握してから利用したいと思います。