J'exécute un petit service Web basé sur python flask, où je veux exécuter une petite requête MySQL. Lorsque j'obtiens une entrée valide pour ma requête SQL, tout fonctionne comme prévu et j'obtiens le mais si la valeur n'est pas stockée dans la base de données, je reçois un 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
J'ai essayé d'exploiter moi-même les erreurs et d'utiliser ce code pour mon projet, mais il semble que cela ne fonctionne pas correctement.
#!/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)
Fondamentalement, je veux simplement retourner une valeur, lorsque tout fonctionne correctement et que je ne veux rien retourner si ce n'est de préférence avec un message d'erreur sur mon serveur. Comment puis-je utiliser correctement la gestion des erreurs?
MODIFIER Code actuel mis à jour + message d'erreur.
Premier point: vous avez trop de code dans votre bloc try/except. Mieux vaut utiliser des blocs try/except distincts lorsque vous avez deux instructions (ou deux groupes d'instructions) qui peuvent générer des erreurs différentes:
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()
Maintenant, devez-vous vraiment attraper une TypeError ici? Si vous lisez à la trace, vous remarquerez que votre erreur provient de l'appel de __getitem__()
sur None
(nb: __getitem__()
est l'implémentation de l'opérateur d'indice []
), Ce qui signifie que si vous n'avez pas de lignes correspondantes cursor.fetchone()
renvoie None
, vous pouvez donc simplement tester le retour de 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()
Maintenant, avez-vous vraiment besoin d'attraper des erreurs MySQL ici? Votre requête est censée être bien testée et ce n'est qu'une opération de lecture, elle ne devrait donc pas planter - donc si vous avez quelque chose qui ne va pas ici, vous avez évidemment un problème plus important et vous ne voulez pas le cacher sous le tapis. IOW: enregistrez les exceptions (en utilisant le package logging
et logger.exception()
) standard et relancez-les ou plus simplement laissez-les se propager (et éventuellement, un composant de niveau supérieur s'occupe de la journalisation non gérée exceptions):
try:
curs.execute(sql)
row = curs.fetchone()
if row:
return row[0]
return None
finally:
conn.close()
Et enfin: la façon dont vous construisez votre requête SQL est absolument dangereux . Utilisez plutôt des espaces réservés sql:
q = "%s%%" % data["email"].strip()
sql = "select userid from oc_preferences where configkey='email' and configvalue like %s"
cursor.execute(sql, [q,])