FlaskでGET、POST、Websocketを行うサンプル
Author: 水卜
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
これらが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は見たまんま。
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})