❇️
خواهشا از HttpClient درست استفاده کنیم! (قسمت اول)
کلاس HttpClient محبوب ترین کلاس برای ارتباطات Http است ولی متاسفانه اکثرا از آن بدستی استفاده نمیکنند!
در این پست میخواهیم Best Practice های آن را بررسی کنیم.
در دات نت، 3 کلاس پایه برای ارتباطات Http داریم :
1️⃣
کلاس HttpWebRequest : اولین و low-level ترین کلاس که کنترل بیشتری به شما می دهد
2️⃣
کلاس WebClient : یک محصور کننده hight-level بر روی HttpWebRequest که کنترل کمتری به شما می دهد ولی طرز استفاده آن ساده تر است
3️⃣
کلاس HttpClient : بهینه ترین کلاس موجود برای ارتباطات Http که مزایای هر دو کلاس قبل را داشته و در دات نت 4.5 به بعد (و نیز تمامی ورژن های NETCore) اضافه شد (البته
پکیج Nuget آن برای دات نت 4.0 هم وجود دارد)
کلاس
HttpClient نسبت به دو کلاس قبلی پرفرمنس بیشتری داشته و متد های اصلی آن (از جمله GetAsync و PostAsync و...)
thread-safe است درنتیجه میتوان یک نسخه از آن به صورت Singleton ایجاد و به صورت concurrent استفاده شود.
یک قابلیت مهم دیگر این آن، امکان Chain کردن
HttpMessageHandlers ها در HttpClient است (چیزی شبیه به Pipeline میدلور ها در ASP Core) که میتوان از آن برای Logging، Caching و Error handling و ... استفاده کرد (
مثال)
4️⃣
کتابخانه RestSharp نیز یک کتابخانه third-party برای ارتباطات Http و مخصوصا REST بوده ولی درون خود از HttpWebRequest استفاده میکند نه HttpClient و
پرفرمنس کمتری دارد (نزدیک به نصف!)
5️⃣
کتابخانه Refit هم هست که با قابلیت های مدرن زیادی داره و کار با RESTful API ها رو خیلی راحت میکنه و البته از HttpClient هم استفاده میکنه
(در حال حاضر بهترین کتابخانه third-party)
🔰 نکته بسیار مهم، استفاده بهینه و صحیح از این کلاس است که متاسفانه خیلی ها به اشتباه از آن استفاده میکنند
🔸کلاس HttpClient نباید هربار و به ازای هر درخواست، ساخته (new) شود که در این صورت پرفرمنس را به شدت کاهش میدهد!
🔹با وجود اینکه استفاده از یک شی Singleton آن نسبت به ایجاد هر باره آن بهتر است ولی باز هم صحیح نیست و باعث میشود
از تغییرات DNS آگاه نشود!
🔸قبلا گفتیم که فقط متد های اصلی آن thread-safe است، پس پروپرتی های آن مانند (DefaultRequestHeaders و BaseAddress و Timeout و ...)
thread-safe نیست و نباید بین ترد های مختلف به صورت مشترک استفاده شود
مثلا اگر یک شی Singleton یا static از HttpClient داشته باشید و در میان ترد های مختلف از آن استفاده کنید ممکن است در آن واحد که یک ترد در حال درخواست زدن به یک url است، ترد دیگری BaseAddress آن را تغییر دهد
🔹با وجود اینکه کلاس کلاس HttpClient یک شی Disposable است ولی نباید به صورت
دستی Dispose شود درنتیجه استفاده از آن در کنار using (برای Dispose خودکار) به شدت اشتباه است و باعث مشکل حادی را به نام
sockets exhaustion (اشباع سوکت های باز) میشود.
🔸نکته قبل، برای خروجی متد های آن، یعنی کلاس HttpResponseMessage صادق نیست و آن هارا باید حتما توسط using یا به صورت دستی Dispose کرد (البته در حالت دستی اگر exception ایی رخ دهد Dispose رخ نخواهد داد پس باید در بلاک try finaly نوشته شود)
🔹نکته بسیار مهم دیگر این است که به هیچ عنوان از کلاس HttpClient به صورت sync استفاده نکنید، ارتباطات network یکی از مهمترین عوامل block کننده thread بوده و دلیل اصلی اینکه کلاس HttpClient فقط و فقط دارای متد های async است همین بوده.
در نتیجه، استفاده از متد های آن به صورت sync همراه با Task.Wait و Task.Result به شدت اشتباه است و باعث بلاک شدن ترد می شود. (این مقوله برای تمامی متد های async صادق است و حتی می تواند باعث dead-lock شود)
در قسمت بعد اصولی ترین و بهینه ترین روش کار با HttpClient را بررسی خواهیم کرد.
#PerformanceTuning #HttpClient
___________