FlaskでGET、POST、Websocketを行うサンプル
 Author: 水卜

実際に動かしてみる

pythonの環境構築はPipenvまたはdockerが現時点でベストだと思っています。

今回はpipenvでやります。

pipenv入れる

pip install pipenv

Pipfile作成

touch Pipfile

Pipfileに以下貼り付け

[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]

[packages]
flask = "*"
gevent = "*"
gevent-websocket = "*"
Flask-Sockets = "*"
gunicorn = "*"
flask-cors = "*"

[requires]
python_version = "3.7"

インストール

pipenv install

main.py作成

import json
from flask import Flask, render_template, request
from flask_cors import CORS
import datetime
import time
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler
from logging import getLogger


websocket = None
logger = getLogger(__name__)
flask = Flask(__name__)
CORS(flask)

# GET
@flask.route('/topics')
def init():
    global app
    return json.dumps(['device1', 'device2'])

# POST
@flask.route('/pay', methods=['POST'])
def pay():
    global app
    data = request.data.decode('utf-8')
    data = json.loads(data)
    return json.dumps({'message': 'received', 'data': data})

# Websocket
@flask.route('/pipe')
def pipe():
    """websocketでメッセージを送信"""
    global app, websocket
    if request.environ.get('wsgi.websocket'):
        websocket = request.environ['wsgi.websocket']
        while True:
            time.sleep(0.1)
            res = websocket.receive()
            logger.info(f'[ws received] {res}')
            data = json.loads(res)
            if data is None:
                break
            websocket.send(json.dumps(
                {'time': str(datetime.datetime.now()), 'message': data['value']}
            ))
    return

if __name__ == "__main__":
    flask.debug = True
    host = 'localhost'
    port = 8080

    server = WSGIServer(
        host,
        port,
        flask,
        handler_class=WebSocketHandler
    )
    server.serve_forever()


起動

pipenv shell
gunicorn -k flask_sockets.worker -b 0.0.0.0:8080 main:flask

解説

web socket

これらがflaskからwebsocketを扱うためのライブラリ

gevent = "*"
gevent-websocket = "*"
Flask-Sockets = "*"
gunicorn = "*"

flaskでwebsocketを使う時はWSGIサーバーのgunicornを使うといいらしい。理由は知らない。

gunicornは名前からして多分unicornの親戚。

unicornはrailsを本番で動かす時に使う。

unicornを使うとmasterと複数のworkerにプロセスを分けて、いい感じに負荷分散できる。

多分gunicornを使うといいのも似たような理由だと思う。

以下はwebsocket部分のコード。

@flask.route('/pipe')
def pipe():
    """websocketでメッセージを送信"""
    global app, websocket
    if request.environ.get('wsgi.websocket'):
        websocket = request.environ['wsgi.websocket']
        while True:
            time.sleep(0.1)
            res = websocket.receive()
            logger.info(f'[ws received] {res}')
            data = json.loads(res)
            if data is None:
                break
            websocket.send(json.dumps(
                {'time': str(datetime.datetime.now()), 'message': data['value']}
            ))
    return

websocketクライアントをglobalに外出ししておけば他の関数で呼べる。

get, post

getとpostは見たまんま。

APIだとpostでもらうリクエストbodyはrequest.dataに入っている。

formからのリクエストの場合、request.formに入っている。

# GET
@flask.route('/topics')
def init():
    global app
    return json.dumps(['device1', 'device2'])

# POST
@flask.route('/pay', methods=['POST'])
def pay():
    global app
    data = request.data.decode('utf-8')
    data = json.loads(data)
    return json.dumps({'message': 'received', 'data': data})