مدیریت خطاهای زمان اجرا (Catching Runtime Errors)
به محض اینکه شروع به اضافه کردن رفتار پویا (Dynamic Behavior) به قالبهای HTML میکنیم، خطر مواجهه با خطاهای زمان اجرا (Runtime Errors) وجود دارد.
بیایید یک خطای عمدی (Deliberate Error) به قالب view.tmpl اضافه کنیم و ببینیم چه اتفاقی میافتد:
{{define "title"}}Snippet #{{.Snippet.ID}}{{end}}
{{define "main"}}
{{with .Snippet}}
<div class='snippet'>
<div class='metadata'>
<strong>{{.Title}}</strong>
<span>#{{.ID}}</span>
</div>
{{len nil}} <!-- Deliberate error -->
<pre><code>{{.Content}}</code></pre>
<div class='metadata'>
<time>Created: {{.Created}}</time>
<time>Expires: {{.Expires}}</time>
</div>
</div>
{{end}}
{{end}}
در کد بالا، خط {{len nil}} را اضافه کردیم که باید در زمان اجرا خطا ایجاد کند زیرا در Go مقدار nil طول ندارد.
حالا برنامه را اجرا کنید. خواهید دید که همه چیز همچنان به درستی کامپایل میشود:
$ go run ./cmd/web time=2024-03-18T11:29:23.000+00:00 level=INFO msg="starting server" addr=:4000
اما اگر با استفاده از curl درخواستی به http://localhost:4000/snippet/view/1 ارسال کنید، پاسخی مشابه این دریافت خواهید کرد:
$ curl -i http://localhost:4000/snippet/view/1
HTTP/1.1 200 OK
Date: Wed, 18 Mar 2024 11:29:23 GMT
Content-Length: 734
Content-Type: text/html; charset=utf-8
<!doctype html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<title>Snippet #1 - Snippetbox</title>
<link rel='stylesheet' href='/static/css/main.css'>
<link rel='shortcut icon' href='/static/img/favicon.ico' type='image/x-icon'>
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700'>
</head>
<body>
<header>
<h1><a href='/'>Snippetbox</a></h1>
</header>
<nav>
<a href='/'>Home</a>
</nav>
<main>
<div class='snippet'>
<div class='metadata'>
<strong>An old silent pond</strong>
<span>#1</span>
</div>
Internal Server Error
این وضعیت بسیار بد است. برنامه ما خطایی ایجاد کرده، اما به کاربر به اشتباه پاسخ 200 OK ارسال شده است. حتی بدتر از آن، کاربر یک صفحه HTML ناقص دریافت کرده است.
برای رفع این مشکل، باید رندر قالب را به یک فرآیند دو مرحلهای تبدیل کنیم. ابتدا باید یک رندر "آزمایشی" با نوشتن قالب در یک بافر انجام دهیم. اگر این کار با خطا مواجه شود، میتوانیم پیام خطا را به کاربر ارسال کنیم. اما اگر موفقیتآمیز باشد، میتوانیم محتوای بافر را به http.ResponseWriter خود بنویسیم.
بیایید تابع کمکی render() را به این روش بهروزرسانی کنیم:
package main import ( "bytes" // New import "fmt" "net/http" ) ... func (app *application) render(w http.ResponseWriter, r *http.Request, status int, page string, data templateData) { ts, ok := app.templateCache[page] if !ok { err := fmt.Errorf("the template %s does not exist", page) app.serverError(w, r, err) return } // Initialize a new buffer. buf := new(bytes.Buffer) // Write the template to the buffer, instead of straight to the // http.ResponseWriter. If there's an error, call our serverError() helper // and then return. err := ts.ExecuteTemplate(buf, "base", data) if err != nil { app.serverError(w, r, err) return } // If the template is written to the buffer without any errors, we are safe // to go ahead and write the HTTP status code to http.ResponseWriter. w.WriteHeader(status) // Write the contents of the buffer to the http.ResponseWriter. Note: this // is another time where we pass our http.ResponseWriter to a function that // takes an io.Writer. buf.WriteTo(w) }
برنامه را مجدداً راهاندازی کنید و همان درخواست را دوباره امتحان کنید. حالا باید یک پیام خطای مناسب و پاسخ 500 Internal Server Error دریافت کنید.
$ curl -i http://localhost:4000/snippet/view/1 HTTP/1.1 500 Internal Server Error Content-Type: text/plain; charset=utf-8 X-Content-Type-Options: nosniff Date: Wed, 18 Mar 2024 11:29:23 GMT Content-Length: 22 Internal Server Error
عالی است. این خیلی بهتر به نظر میرسد.
قبل از اینکه به فصل بعدی برویم، به فایل view.tmpl برگردید و خطای عمدی را حذف کنید:
{{define "title"}}Snippet #{{.Snippet.ID}}{{end}}
{{define "main"}}
{{with .Snippet}}
<div class='snippet'>
<div class='metadata'>
<strong>{{.Title}}</strong>
<span>#{{.ID}}</span>
</div>
<pre><code>{{.Content}}</code></pre>
<div class='metadata'>
<time>Created: {{.Created}}</time>
<time>Expires: {{.Expires}}</time>
</div>
</div>
{{end}}
{{end}}
واژهنامه اصطلاحات فنی
| اصطلاح فارسی | معادل انگلیسی | توضیح |
|---|---|---|
| خطاهای زمان اجرا | Runtime Errors | خطاهایی که در حین اجرای برنامه رخ میدهند |
| رفتار پویا | Dynamic Behavior | عملکردی که در زمان اجرا تغییر میکند |
| خطای عمدی | Deliberate Error | خطایی که به قصد تست سیستم ایجاد میشود |
| مدیریت خطا | Error Handling | روشهای کنترل و پاسخ به خطاها |
| پیام خطا | Error Message | توضیحی درباره خطای رخ داده |
| خطای قالب | Template Error | خطایی که در پردازش قالب رخ میدهد |
| تست خطا | Error Testing | بررسی واکنش سیستم به شرایط خطا |
| گزارش خطا | Error Reporting | نمایش و ثبت اطلاعات خطاها |
| بازیابی از خطا | Error Recovery | اقدامات لازم پس از رخداد خطا |
| پیشگیری از خطا | Error Prevention | روشهای جلوگیری از وقوع خطا |