質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Heroku

HerokuはHeroku社が開発と運営を行っているPaaSの名称です。RubyやNode.js、Python、そしてJVMベース(Java、Scala、Clojureなど)の複数のプログラミング言語をサポートしている。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

SSL

SSL(Secure Sockets Layer)とは、暗号化されたプロトコルで、インターネット上での通信セキュリティを提供しています。

Q&A

0回答

1578閲覧

herokuにデプロイしたアプリケーションを動かしてDBにクエリを渡すと、SSLのエラーが発生する

enix3

総合スコア1

Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Heroku

HerokuはHeroku社が開発と運営を行っているPaaSの名称です。RubyやNode.js、Python、そしてJVMベース(Java、Scala、Clojureなど)の複数のプログラミング言語をサポートしている。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

SSL

SSL(Secure Sockets Layer)とは、暗号化されたプロトコルで、インターネット上での通信セキュリティを提供しています。

0グッド

0クリップ

投稿2021/02/10 12:29

編集2021/02/11 05:19

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

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2021/02/10 12:46

なんか接続情報が書いてありますけど…。パスワードリセットをお勧めします。
enix3

2021/02/10 13:00

ご指摘いただきありがとうございます。修正いたしました。。
hoshi-takanori

2021/02/10 21:47

その接続情報を使うと、ローカル環境から ClearDB (heroku の MySQL) に接続できるので、まず mysql コマンドで直接繋がることを確認した上で、ローカルの flask から動作確認できるはず。 (また、念のため確認ですが、teratail は編集履歴が残るので、パスワード変更は必須です。)
enix3

2021/02/11 04:14

ローカル環境から、python app.py を叩いてブラウザからlocalhostに接続し、諸々の操作をしましたが 正常に動くことを確認いたしました。 また、mysqlコマンドを使用したログインやSELECT,INSERTといったクエリの操作も可能でした。 現在はClearDBのダッシュボードからSSL証明書を取得し、mysql.connectorに渡して接続できるかどうかを試しているところです。 (パスワードは変更致しました。気にかけて下さり有難うございます。)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問