logに吐かれたエラー内容がよくわからないので質問させてください。
flask + Mysql + python + フロントサイドで
会員制の行動記録アプリを作成しました。
機能は、「会員登録・ログイン・行動記録の記録・過去の行動履歴参照」を持ちます。
どの機能もMySQLで作成したデータベースを参照して値の追加・返却を行います。
localhostでは動作確認が取れましたが
herokuにデプロイして動作確認を行うと、以下のエラーを吐きました。
(画面上は500Errorです。)
system error: 1 [SSL: UNSUPPORTED_PROTOCOL] unsupported protocol
なお、herokuにSSLの設定を入れましたが、同様のエラーを吐きました。。。。。。
色々と勉強不足で、ところどころ見様見真似で作成したのでコードはかなり可読性低いです。
今後メンテしていく予定です...
ミドルウェアの設定や使用すべきライブラリが誤っているなど、
同様のエラーに出会ったことのある方がいらっしゃいましたら
ヒントや解決策をご教示いただけますと幸いです。
情報の不足している点がございましたら何なりとお申し付けください。
使用環境
windows10
Flask==1.1.2
mysql-connector-python==8.0.23
Python 3.7.3
gunicorn==20.0.4
oauthlib==3.1.0
requests-oauthlib==1.3.0
log
1File "/app/.heroku/python/lib/python3.6/site-packages/mysql/connector/network.py", line 522, in switch_to_ssl 22021-02-10T11:27:56.880221+00:00 app[web.1]: errno=2055, values=(self.get_address(), _strioerror(err))) 32021-02-10T11:27:56.880228+00:00 app[web.1]: mysql.connector.errors.InterfaceError: 2055: Lost connection to MySQL server at 'us-cdbr-east-03.cleardb.com:3306', system error: 1 [SSL: UNSUPPORTED_PROTOCOL] unsupported protocol (_ssl.c:852)
↓app.py(メイン)
Python
1from flask import Flask, url_for, redirect, render_template, request, Markup, session 2from functools import wraps 3from DataStore.MySQL import MySQL 4import mysql.connector, re, os, time, datetime, hashlib, base64, random, string 5 6# 日付関数 7dt_now = datetime.datetime.now() 8 9# 証明書のディレクトリ指定 10dirname = os.getcwd() 11if os.name == 'nt': 12 print("on windows") 13 ca_path = os.path.join(dirname, 'opt\mysql\ssl\ca.pem') 14 cert_path = os.path.join(dirname, 'opt\mysql\ssl\client-cert.pem') 15 key_path = os.path.join(dirname, 'opt\mysql\ssl\client-key.pem') 16elif os.name == 'posix': 17 print("on mac or linux") 18 ca_path = os.path.join(dirname, 'opt/mysql/ssl/ca.pem') 19 cert_path = os.path.join(dirname, 'opt/mysql/ssl/client-cert.pem') 20 key_path = os.path.join(dirname, 'opt/mysql/ssl/client-key.pem') 21 22 23 24# DBとDBにログインするユーザの定義 25dns = { 26 'user': 'XXXX', 27 'host': 'us-cdbr-east-03.cleardb.com', 28 'password': 'XXXX', 29 'database': 'heroku_5c65651484c4266' 30 # 以下追加。 31 'client_flags': [ClientFlag.SSL], 32 'ssl_ca': ca_path, 33 'ssl_cert': cert_path, 34 'ssl_key': key_path 35} 36db = MySQL(**dns) 37 38# ランダム文字列生成 39def randomname(n): 40 randlst = [random.choice(string.ascii_letters + string.digits) for i in range(n)] 41 return ''.join(randlst) 42 43# Flaskインスタンスと暗号化キーの指定 44app = Flask(__name__) 45app.secret_key = randomname(16) 46 47# saltの生成&パスワードへの付与 48def gen_password(pwd): 49 salt = os.urandom(16) 50 digest = hashlib.pbkdf2_hmac('sha256', 51 pwd.encode('utf-8'), salt, 10000) 52 return base64.b64encode(salt + digest).decode('ascii') 53 54# パスワード検証 55def verify_password(pwd, hash): 56 b = base64.b64decode(hash) 57 salt, digest_v = b[:16], b[16:] 58 digest_n = hashlib.pbkdf2_hmac('sha256', 59 pwd.encode('utf-8'), salt, 10000) 60 return digest_n == digest_v 61 62# ログイン画面 63@app.route('/') 64def main(): 65 props = {'title': 'login or sign up', 'msg': 'ユーザ登録&ログイン'} 66 return render_template('index.html', props=props) 67 68# ユーザ登録画面に遷移 69@app.route('/regist_user') 70def regist_user(): 71 props = {'title': 'sign up', 'msg': 'ユーザ登録'} 72 html = render_template('user_regist.html', props=props) 73 return html 74 75# ユーザー登録 76@app.route('/register', methods=['POST']) 77def register(): 78 name = request.form.get('name') 79 age = request.form.get('age') 80 gender = request.form.get('gender') 81 pwd = request.form.get('pwd') 82 # パスワードはハッシュ化する 83 hash_pwd = gen_password(pwd) 84 # ユーザーを追加 85 add_result = add_user(name, age, gender, hash_pwd) 86 if add_result: 87 props = {'title': 'success sign up', 'msg': 'ユーザを登録しました!'} 88 return render_template('msg.html', props=props) 89 else: 90 props = {'title': 'failed sign up', 'msg': 'ユーザの登録に失敗しました。'} 91 return render_template('msg.html', props=props) 92 93# DBにユーザ追加 94def add_user(name, age, gender, pwd): 95 # 別モジュールに渡すことに。 96 stmt = 'INSERT INTO users (name, age, gender, password) VALUES (?, ?, ?, ?)' 97 reg = db.ins_query(stmt, name, age, gender, pwd, prepared=True) 98 if reg: 99 return True 100 else: 101 return False 102 103# ログイン画面に遷移 104@app.route('/login') 105def login(): 106 props = {'title': 'try login', 'msg': 'ログイン試行'} 107 return render_template('login_form.html', props=props) 108 109# ログイントライ 110@app.route('/login/try', methods=['POST']) 111def login_try(): 112 name = request.form.get('name') 113 pwd = request.form.get('pwd') 114 result = check_user(name, str(pwd)) 115 if result: 116 session['login'] = name 117 return redirect('/user/home') 118 else: 119 props = {'title': 'login failed', 'msg': 'ログインに失敗しました。ユーザ名かパスワードが誤っています'} 120 return render_template('msg.html', props=props) 121 122# ログイン成功→ユーザーHOME画面 123@app.route('/user/home') 124def login_success(): 125 name = get_name() 126 # ログイン先の画面(user_home.html)に遷移さす。 127 props = {'title': 'user_home', 'msg':'あなたのマイページ'} 128 return render_template('user_home.html', name=name, props=props) 129 130# DBからログイン情報参照 レコードのCOUNT結果で存在有無を判断する! 131def check_user(name, pwd): 132 stmt = 'SELECT COUNT(*) FROM users WHERE name=?' 133 log = db.query(stmt, name, prepared=True) 134 if 1 in log[0]: 135 stmt = 'SELECT password FROM users WHERE name=?' 136 hash_pwd = db.query(stmt, name, prepared=True) 137 return verify_password(str(pwd), str(hash_pwd[0])) 138 else: 139 return False 140 141 142# セッション管理 143def is_login(): 144 return 'login' in session 145 146# ユーザ名の取得 147def get_name(): 148 return session['login'] 149 if not is_login(): 150 'not login' 151 152 153# ログアウト処理 154@app.route('/logout') 155def logout(): 156 try_logout() 157 props = {'title': 'logout', 'msg': 'お疲れ様でした(⌒,_ゝ⌒)'} 158 return render_template('msg.html', props=props) 159 160# ログアウトトライ 161def try_logout(): 162 session.pop('login', None) 163 164# ログイン必須を処理するデコレーターを定義 165def login_required(func): 166 @wraps(func) 167 def wrapper(*args, **kwargs): 168 if not is_login(): 169 return redirect('/login') 170 return func(*args, **kwargs) 171 return wrapper 172 173 174# 過去の記録確認 175@app.route('/user/old_log') 176@login_required 177def check_old_log(): 178 name = get_name() 179 dt = get_today() 180 props = {'title': 'user old log', 'msg': '過去の記録確認'} 181 stmt = 'SELECT memo, dt, tm FROM users_log\ 182 WHERE name = ? AND dt = cast(now() as date)' 183 timeline = db.query(stmt, name, prepared=True) 184 return render_template('user_old_log.html', 185 name=name, dt=dt,timeline=timeline, props=props) 186 187# カレンダーに入力された日付を取得し、タイムラインを再表示する。 188@app.route('/user/old_log', methods=['POST']) 189@login_required 190def check_calendar(): 191 name = get_name() 192 dt = request.form.get('date') 193 props = {'title': 'user old log', 'msg': '過去の記録確認'} 194 stmt = 'SELECT memo, dt, tm FROM users_log\ 195 WHERE name = ? AND dt = ?' 196 timeline = db.query(stmt, name, dt, prepared=True) 197 return render_template('user_old_log.html', 198 name=name, dt=dt, timeline=timeline, props=props) 199 200 201# 記録を作成する! 202@app.route('/user/add_log') 203@login_required 204def add_log(): 205 props = {'title': 'write log', 'msg': '今この瞬間の出来事・気持ちなどを記録しよう'} 206 return render_template('user_add_log.html', 207 name=get_name(), props=props) 208 209@app.route('/user/add_log', methods=['POST']) 210@login_required 211def write_log(): 212 name = get_name() 213 memo = request.form.get('text') 214 dt = get_today() 215 tm = get_time() 216 props = {'title': 'success write log', 'msg': '記録出来ました!この調子!'} 217 stmt = 'INSERT INTO users_log values\ 218 (?, ?, ?, ?);' 219 write_log = db.ins_query(stmt, name, memo, dt, tm, prepared=True) 220 return render_template('user_add_log.html', 221 name=name, memo=memo, dt=dt, tm=tm, props=props) 222 223 224# 今日日付取得 225def get_today(): 226 d = datetime.datetime.now() 227 today = (d.strftime('%Y-%m-%d')) 228 return today 229 230# 現在時刻取得 231def get_time(): 232 t = datetime.datetime.now() 233 time = (t.strftime('%H:%M:%S')) 234 return time 235 236@app.errorhandler(404) 237def not_found(error): 238 return redirect(url_for('main')) 239 240if __name__ == '__main__': 241 app.run(debug=True)
MySQL.py
python
1import mysql.connector 2 3class MySQL: 4 def __init__(self, **dns): 5 self.dns = dns 6 self.dbh = None 7 8 def _open(self): 9 self.dbh = mysql.connector.MySQLConnection(**self.dns) 10 11 def _close(self): 12 self.dbh.close() 13 14 def query(self, stmt, *args, **kwargs): #ユーザ, クエリ, 15 self._open() 16 if kwargs.get('prepared', False): 17 cursor = self.dbh.cursor(prepared=True) 18 cursor.execute(stmt, args) 19 else: 20 cursor = self.dbh.cursor() 21 cursor.execute(stmt) 22 data = cursor.fetchall() 23 cursor.close() 24 self._close() 25 return data 26 27 def ins_query(self, stmt, *args, **kwargs): 28 self._open() 29 if kwargs.get('prepared', False): 30 cursor = self.dbh.cursor(prepared=True) 31 cursor.execute(stmt, args) 32 else: 33 cursor = self.dbh.cursor() 34 cursor.execute(stmt) 35 # data = cursor.fetchall() 36 self.dbh.commit() 37 cursor.close() 38 return True 39
あなたの回答
tips
プレビュー