چگونه در Flask خطاها را مدیریت کنیم و صفحات خطای سفارشی بسازیم؟

Flask یک فریم‌ورک سبک‌وزن وب پایتون است که ابزارها و امکانات مفیدی برای ساخت برنامه‌های وب در زبان پایتون فراهم می‌کند.

در هنگام توسعه یک برنامه وب، قطعاً با موقعیت‌هایی مواجه خواهید شد که برنامه شما برخلاف انتظار عمل می‌کند. ممکن است متغیری را اشتباه تایپ کنید، یک حلقه for را نادرست استفاده کنید، یا یک شرط if به گونه‌ای نوشته شده باشد که یک استثنا در پایتون ایجاد کند، مانند فراخوانی تابع قبل از تعریف آن یا جستجوی صفحه‌ای که وجود ندارد. اگر یاد بگیرید چگونه خطاها و استثناها را به درستی مدیریت کنید، فرآیند توسعه برنامه‌های Flask برای شما آسان‌تر و روان‌تر خواهد بود.

در این آموزش، یک برنامه کوچک وب می‌سازید که نحوه مدیریت خطاهای رایج در توسعه برنامه‌های وب را نشان می‌دهد. شما صفحات خطای سفارشی ایجاد می‌کنید، از دیباگر Flask برای عیب‌یابی استثناها استفاده می‌کنید و برای پیگیری رویدادها در برنامه خود از لاگ‌گیری بهره می‌برید.

نیازمندی‌ها

  • یک محیط برنامه‌نویسی محلی پایتون 3. می‌توانید آموزش نصب و راه‌اندازی محیط برنامه‌نویسی محلی برای پایتون 3 را دنبال کنید. در این آموزش، دایرکتوری پروژه را flask_app می‌نامیم.
  • درک مفاهیم پایه‌ای Flask مانند routes، توابع view و قالب‌ها. اگر با Flask آشنا نیستید، مطالب «ایجاد اولین برنامه وب با Flask و پایتون» و «استفاده از قالب‌ها در برنامه Flask» را مطالعه کنید.
  • آشنایی با مفاهیم پایه HTML. می‌توانید سری آموزش «ساخت وبسایت با HTML» را برای کسب دانش پایه مرور کنید.

گام اول: اجرای برنامه Flask با خطاهای اولیه و فعال کردن حالت دیباگ

ابتدا برنامه‌ای که شامل چند خطا است را ایجاد کرده و بدون حالت دیباگ آن را اجرا کنید تا ببینید برنامه چگونه واکنش نشان می‌دهد. سپس برنامه را با حالت دیباگ روشن اجرا کرده و از دیباگر برای عیب‌یابی خطاها استفاده کنید.

با فعال بودن محیط برنامه‌نویسی و نصب Flask، فایلی به نام app.py در دایرکتوری flask_app باز کنید و کد زیر را وارد نمایید:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html")

در کد بالا، ابتدا کلاس Flask را از پکیج flask وارد کرده‌اید. سپس نمونه‌ای از برنامه Flask با نام app ایجاد کرده‌اید. با دکوراتور @app.route() یک تابع view با نام index() ساختید که تابع render_template() را برای نمایش قالب index.html فراخوانی می‌کند. دو خطا در این کد وجود دارد: اولین خطا این است که تابع render_template() وارد نشده و دوم اینکه فایل قالب index.html وجود ندارد.

فایل را ذخیره و ببندید.

سپس باید Flask را به برنامه اطلاع دهید که چه فایلی سرور را راه‌اندازی کند. در خط فرمان، متغیر محیطی FLASK_APP را با دستور زیر تنظیم کنید (در ویندوز به جای export از set استفاده کنید):

export FLASK_APP=app.py

سپس سرور برنامه را با دستور زیر اجرا کنید:

flask run

پیام‌های زیر در ترمینال ظاهر خواهند شد:

  • برنامه Flask که ارائه می‌شود (در این مثال app.py)
  • محیط که در این مثال پرو덕شن است. هشدار داده شده که این سرور برای اجرا در محیط تولید مناسب نیست. شما در حال استفاده از آن برای توسعه هستید، پس می‌توانید این هشدار را نادیده بگیرید.
  • حالت دیباگ خاموش است، یعنی دیباگر Flask فعال نیست و پیام‌های خطای مفیدی در دسترس نخواهید داشت. در محیط تولید نشان دادن خطاهای دقیق ریسک امنیتی دارد.
  • سرور روی آدرس http://127.0.0.1:5000/ اجرا می‌شود. برای متوقف کردن سرور از Ctrl+C استفاده کنید.

اکنون در مرورگر صفحه اصلی را باز کنید:

صفحه خطای 500 Internal Server Error نمایش داده می‌شود که معنی آن خطای سرور به علت مشکلی داخلی در کد برنامه است.

در ترمینال خطاهایی به صورت زیر نشان داده خواهد شد:

NameError: name 'render_template' is not defined

این یعنی تابع render_template() وارد نشده است.

برای آسان‌تر کردن عیب‌یابی، حالت دیباگ را فعال کنید. برای این کار سرور را با Ctrl+C متوقف و سپس متغیر محیطی FLASK_ENV را روی development تنظیم کنید (در ویندوز از set استفاده کنید):

export FLASK_ENV=development

سرور را دوباره اجرا کنید:

flask run

متوجه می‌شوید که محیط توسعه فعال شده، حالت دیباگ روشن و پنجره دیباگر فعال است. همچنین یک Debugger PIN مشاهده می‌کنید که برای باز کردن کنسول تعاملی در مرورگر استفاده می‌شود.

صفحه را رفرش کنید و خطا به شکل واضح‌تری نمایش داده می‌شود. همچنین این امکان وجود دارد تا در کنسول دیباگر کد پایتون را به صورت تعاملی اجرا کنید (نیازی به استفاده از آن در این آموزش نیست).

برای رفع این مشکل، فایل app.py را باز کرده و آن را به صورت زیر ویرایش کنید:

from flask import Flask, render_template

app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html")

تغییر داده شده تا تابع render_template() وارد شود. حالا با اجرای مجدد سرور و رفرش صفحه، خطای مربوط به نبود تابع حذف شده اما خطای دیگری خواهید داشت که نشان می‌دهد فایل قالب index.html وجود ندارد.

گام دوم: ایجاد قالب‌ها و صفحه اصلی

برای رفع خطای قالب، ابتدا یک قالب پایه base.html ایجاد می‌کنیم که سایر قالب‌ها از آن ارث‌بری می‌کنند و از تکرار کد جلوگیری می‌کند.

در فولدر پروژه، پوشه‌ای به نام templates بسازید (Flask به صورت پیش‌فرض قالب‌ها را در اینجا می‌جوید).

فایل base.html را بسازید و کد زیر را در آن قرار دهید:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title><block title>ParminCloud App</block></title>
</head>
<body>
  <nav>
    <a href="{{ url_for('index') }}">Home</a> |
    <a href="#">About</a>
  </nav>
  <hr>
  <block content></block>
</body>
</html>

پس از آن، فایل index.html را بسازید و کد زیر را در آن وارد کنید:

{% extends "base.html" %}

{% block title %}Home - ParminCloud App{% endblock %}

{% block content %}
  <h1>Welcome to ParminCloud!</h1>
  <h2>Hello, Flask!</h2>
{% endblock %}

اکنون اگر سرور در حالت توسعه روشن باشد و صفحه را رفرش کنید، صفحه اصلی بارگذاری می‌شود بدون خطا.

گام سوم: مدیریت درخواست‌های abort و صفحات خطای سفارشی

اکنون می‌خواهیم در صورت درخواست داده‌ای که وجود ندارد، با خطای 404 پاسخ دهیم و صفحات خطای سفارشی بسازیم.

ابتدا در app.py یک مسیر جدید برای نمایش پیام‌ها اضافه کنید:

@app.route("/messages/<int:idx>")
def message(idx):
    messages = ["Message Zero", "Message One", "Message Two"]
    return render_template("message.html", message=messages[idx])

فایل قالب message.html را جدید بسازید و کد زیر را در آن قرار دهید:

{% extends "base.html" %}

{% block title %}Messages - ParminCloud App{% endblock %}

{% block content %}
  <h1>Messages</h1>
  <h2>{{ message }}</h2>
{% endblock %}

حالت فعلی، درخواست با idx بزرگ‌تر از 2 باعث بروز خطای IndexError خواهد شد که به صورت خطای 500 پاسخ داده می‌شود. اما پاسخ صحیح، 404 Not Found است.

برای این منظور تابع abort() را از flask وارد کرده و تابع message را مانند زیر اصلاح می‌کنیم:

from flask import abort

@app.route("/messages/<int:idx>")
def message(idx):
    messages = ["Message Zero", "Message One", "Message Two"]
    try:
        return render_template("message.html", message=messages[idx])
    except IndexError:
        abort(404)

حالا اگر مسیر مربوط به پیام ناموجود را باز کنید، صفحه خطای 404 نمایش داده خواهد شد.

ایجاد صفحات خطای سفارشی 404 و 500

در app.py توابع مدیریت خطا را اضافه کنید:

@app.errorhandler(404)
def page_not_found(error):
    return render_template("404.html"), 404

@app.errorhandler(500)
def internal_error(error):
    return render_template("500.html"), 500


@app.route("/500")
def error500():
    abort(500)

سپس قالب 404.html را با کد زیر بسازید:

{% extends "base.html" %}

{% block title %}404 Not Found - ParminCloud App{% endblock %}

{% block content %}
  <h1>404 - Page Not Found</h1>
  <p>The page you are looking for does not exist.</p>
  <p>Please check the URL or return to the home page.</p>
{% endblock %}

و قالب 500.html را با کد زیر بسازید:

{% extends "base.html" %}

{% block title %}500 Internal Server Error - ParminCloud App{% endblock %}

{% block content %}
  <h1>500 - Internal Server Error</h1>
  <p>An unexpected error has occurred.</p>
  <p>Please try again later or contact support.</p>
{% endblock %}

حالا اگر به مسیر /500 بروید، صفحه خطای 500 سفارشی نمایش داده خواهد شد و هر خطای داخلی نیز صفحه 500 سفارشی را نمایش می‌دهد.

استفاده از logging برای پیگیری رویدادها

برای کمک به عیب‌یابی و درک عملکرد برنامه، می‌توانیم از لاگ‌گیری استفاده کنیم. تابع app.logger در Flask قابلیت لاگ‌گیری با سطوح مختلف را دارد.

برای مثال تابع message() را به صورت زیر ویرایش کنید تا رویدادهای لاگ شده در ترمینال نمایش داده شوند:

def message(idx):
    messages = ["Message Zero", "Message One", "Message Two"]
    app.logger.info("Accessed messages page")
    app.logger.debug(f"Fetching message with index: {idx}")
    try:
        return render_template("message.html", message=messages[idx])
    except IndexError:
        app.logger.error(f"Message index out of range: {idx}")
        abort(404)

اکنون اگر به مسیرهای پیام‌های معتبر مراجعه کنید، لاگ‌های INFO و DEBUG را در ترمینال می‌بینید و در صورت آدرس نامعتبر، پیام خطا ERROR هم ثبت می‌شود.

جمع‌بندی

در این آموزش، یاد گرفتید چگونه حالت دیباگ Flask را فعال کرده و از آن برای عیب‌یابی خطاها استفاده کنید. همچنین آموختید چطور درخواست‌ها را abort و با پیام خطای مناسب پاسخ دهید و صفحات خطای سفارشی بسازید. در نهایت، نحوه استفاده از لاگ‌گیری در Flask را یاد گرفتید تا رفتار برنامه را بهتر درک و مشکلات را راحت‌تر شناسایی کنید.

از همراهی شما با پارمین کلود سپاسگذاریم.

Click to rate this post!
[Total: 0 Average: 0]

نظرات کاربران

دیدگاهی بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *