pythonフラスコ、小さなMySQLクエリを実行するフラスコに基づく小さなWebサービスを実行しています。SQLクエリの有効な入力を取得すると、すべてが期待どおりに動作し、ただし、値がデータベースに保存されていない場合、TypeError
を受け取ります
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1478, in full_dispatch_request
response = self.make_response(rv)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1566, in make_response
raise ValueError('View function did not return a response')
ValueError: View function did not return a response
私は自分でエラー処理を利用して、このコードをプロジェクトに使用しようとしましたが、これは正しく機能しないようです。
#!/usr/bin/python
from flask import Flask, request
import MySQLdb
import json
app = Flask(__name__)
@app.route("/get_user", methods=["POST"])
def get_user():
data = json.loads(request.data)
email = data["email"]
sql = "SELECT userid FROM oc_preferences WHERE configkey='email' AND configvalue LIKE '" + email + "%';";
conn = MySQLdb.connect( Host="localhost",
user="root",
passwd="ubuntu",
db="owncloud",
port=3306)
curs = conn.cursor()
try:
curs.execute(sql)
user = curs.fetchone()[0]
return user
except MySQLdb.Error, e:
try:
print "MySQL Error [%d]: %s" % (e.args[0], e.args[1])
return None
except IndexError:
print "MySQL Error: %s" % str(e)
return None
except TypeError, e:
print(e)
return None
except ValueError, e:
print(e)
return None
finally:
curs.close()
conn.close()
if __name__ == "__main__":
app.run(Host="0.0.0.0", port=5000, debug=True)
基本的には、すべてが正常に機能しているときに値を返したいだけで、サーバーにエラーメッセージが表示されない場合は何も返しません。エラー処理を適切な方法で使用するにはどうすればよいですか?
[〜#〜] edit [〜#〜]現在のコードとエラーメッセージを更新しました。
最初のポイント:try/exceptブロックにコードが多すぎます。異なるエラーを発生させる可能性のある2つのステートメント(または2つのステートメントグループ)がある場合は、個別のtry/exceptブロックを使用する方が適切です。
try:
try:
curs.execute(sql)
# NB : you won't get an IntegrityError when reading
except (MySQLdb.Error, MySQLdb.Warning) as e:
print(e)
return None
try:
user = curs.fetchone()[0]
return user
except TypeError as e:
print(e)
return None
finally:
conn.close()
ここで本当にTypeErrorをキャッチする必要がありますか?トレースバックを読むと、エラーはNone
で__getitem__()
を呼び出すことに起因することに気付くでしょう(nb:__getitem__()
は添え字演算子[]
の実装です)。つまり、一致する行がない場合はcursor.fetchone()
がNone
を返すので、currsor.fetchone()
の戻り値をテストするだけです。
try:
try:
curs.execute(sql)
# NB : you won't get an IntegrityError when reading
except (MySQLdb.Error, MySQLdb.Warning) as e:
print(e)
return None
row = curs.fetchone()
if row:
return row[0]
return None
finally:
conn.close()
ここで本当にMySQLエラーをキャッチする必要がありますか?クエリは十分にテストされており、読み取り操作にすぎないため、クラッシュすることはありません。ここで何か問題が発生した場合、明らかに大きな問題があり、それをカーペットの下に隠したくありません。 IOW:例外をログに記録して(標準のlogging
パッケージとlogger.exception()
を使用して)、またはそれらを単純に伝播させます(最終的には、より高いレベルのコンポーネントが未処理のログを処理します)例外):
try:
curs.execute(sql)
row = curs.fetchone()
if row:
return row[0]
return None
finally:
conn.close()
最後に、SQLクエリを作成する方法は まったく安全ではない です。代わりにSQLプレースホルダーを使用します。
q = "%s%%" % data["email"].strip()
sql = "select userid from oc_preferences where configkey='email' and configvalue like %s"
cursor.execute(sql, [q,])