معماری CQRS و چالش پروتکل HTTP: آیا می‌توان در Ajax فقط از POST استفاده کرد؟

معماری CQRS (Command Query Responsibility Segregation) یکی از الگوهای محبوب در طراحی سیستم‌های نرم‌افزاری پیچیده است که اصل جداسازی مدل‌های خواندن (Query) و نوشتن (Command) را مطرح می‌کند. در پیاده‌سازی این الگو در بستر وب (Web API)، معمولاً سوالاتی درباره نحوه نگاشت این مفاهیم به متدهای استاندارد HTTP (مانند GET، POST، PUT و DELETE) پیش می‌آید. یکی از سوالات چالش‌برانگیز و جذاب این است: آیا می‌توانیم تمام تعاملات بین کلاینت (Ajax/Frontend) و سرور را صرفاً با استفاده از متد POST انجام دهیم؟
کینگتو - آموزش برنامه نویسی تخصصصی - دات نت - سی شارپ - بانک اطلاعاتی و امنیت

معماری CQRS و چالش پروتکل HTTP: آیا می‌توان در Ajax فقط از POST استفاده کرد؟

20 بازدید 0 نظر ۱۴۰۴/۰۹/۰۲

۱. مقدمه‌ای بر CQRS و استانداردهای HTTP

برای درک عمیق موضوع، ابتدا باید نگاهی کوتاه به نحوه تعامل CQRS با پروتکل وب داشته باشیم.

 

فلسفه CQRS

در CQRS، ما با سیستم به دو روش متفاوت رفتار می‌کنیم:

  1. Commands (دستورات): قصد انجام کاری را دارند که منجر به تغییر وضعیت سیستم می‌شود (مانند ثبت سفارش، تغییر رمز عبور). این عملیات معمولاً خروجی داده‌ای ندارند (void) یا فقط شناسه تولید شده را برمی‌گردانند.

  2. Queries (پرس‌وجوها): قصد دریافت اطلاعات را دارند بدون اینکه وضعیت سیستم را تغییر دهند (مانند دریافت لیست محصولات). این عملیات باید Idempotent (تکرارپذیر بدون تغییر نتیجه) و Safe (بدون عوارض جانبی) باشند.

 

نگاشت استاندارد به REST

در یک API که سعی دارد اصول RESTful را رعایت کند، نگاشت معمول به صورت زیر است:

  • Query $\rightarrow$ GET: چون وضعیت را تغییر نمی‌دهد و باید کش‌پذیر (Cacheable) باشد.

  • Command $\rightarrow$ POST, PUT, DELETE, PATCH: چون وضعیت را تغییر می‌دهند.

 

۲. فرضیه "فقط POST": آیا امکان‌پذیر است؟

پاسخ کوتاه و فنی به سوال شما «بله» است.

در دنیای توسعه وب، هیچ مانع فنی سخت‌افزاری یا نرم‌افزاری وجود ندارد که شما را از ارسال یک درخواست برای دریافت داده (Query) با متد POST منع کند. در واقع، بسیاری از پروتکل‌های مدرن و قدیمی دقیقا همین کار را انجام می‌دهند:

  • SOAP: تمام درخواست‌ها را (چه خواندن و چه نوشتن) در قالب XML و با متد POST ارسال می‌کند.

  • GraphQL: به‌صورت پیش‌فرض، تمام کوئری‌ها و میوتیشن‌ها (Mutations) را با متد POST به یک اندپوینت واحد (مثلاً /graphql) ارسال می‌کند.

  • JSON-RPC: از POST برای فراخوانی متدها روی سرور استفاده می‌کند.

بنابراین، شما می‌توانید یک معماری Ajax طراحی کنید که در آن کلاینت برای هر کاری (ثبت نام کاربر، گرفتن لیست اخبار، جستجو) فقط و فقط از POST استفاده کند. به این تکنیک اصطلاحاً HTTP Tunneling گفته می‌شود، زیرا شما تمام نیت‌های خود را از طریق تونل POST عبور می‌دهید و معنای متدهای HTTP را نادیده می‌گیرید.

 

۳. چرا در معماری CQRS معمولاً برای کامندها از POST استفاده می‌شود؟

استفاده از POST برای Command‌ها در CQRS دلایل محکمی دارد:

  1. ماهیت غیرادمپوتنت (Non-Idempotent): متد POST ذاتاً به این معنی است که "این داده را پردازش کن". اگر شما دو بار یک درخواست CreateOrder را با POST بفرستید، منطقاً باید دو سفارش ایجاد شود (مگر اینکه مکانیزم‌های جلوگیری از تکرار در سرور داشته باشید). این با ماهیت اکثر کامندها همخوانی دارد.

  2. بدنه درخواست (Payload): کامندها معمولاً حاوی داده‌های پیچیده (JSON) هستند. متد POST استانداردترین مکان برای حمل این داده‌ها در Body درخواست است.

  3. امنیت: داده‌های ارسال شده در Body (برخلاف URL در متد GET) در تاریخچه مرورگر یا لاگ‌های ساده سرور (Access Logs) ذخیره نمی‌شوند.

 

۴. چالش‌های استفاده از POST برای کوئری‌ها (Queries)

اگر تصمیم بگیرید در معماری CQRS خود، برای بخش خواندن اطلاعات (Query) نیز از POST استفاده کنید (استراتژی فقط-POST)، با چالش‌های جدی مواجه خواهید شد که باید آن‌ها را مدیریت کنید.

 

الف) از دست دادن کش مرورگر و CDN (مهم‌ترین چالش)

پروتکل HTTP به گونه‌ای طراحی شده است که متد GET کش‌پذیر (Cacheable) باشد. مرورگرها، پروکسی‌سرورها و CDNها (مانند Cloudflare) به‌طور خودکار پاسخ‌های GET را بر اساس هدرهای کش ذخیره می‌کنند.

  • مشکل: متد POST به‌طور پیش‌فرض کش نمی‌شود. اگر لیست محصولات را با POST بگیرید، هربار که کاربر صفحه را رفرش کند، درخواست واقعاً به سرور شما برخورد می‌کند و دیتابیس درگیر می‌شود.

  • راه‌حل: پیاده‌سازی کش سمت کلاینت (در حافظه JavaScript یا LocalStorage) یا استفاده از هدرهای خاص برای مجبور کردن کش‌های میانی (که پیچیده و گاهی غیرممکن است).

 

ب) نقض اصول معنایی (Semantics)

وب بر اساس اصول معنایی بنا شده است. وقتی یک درخواست GET /products/123 ارسال می‌شود، هر مهندس نرم‌افزار یا ابزار مانیتورینگی می‌فهمد که این یک درخواست خواندن است.

  • مشکل: وقتی همه چیز POST باشد، لاگ‌های سرور شما پر از درخواست‌های POST می‌شود و تشخیص اینکه کدام‌یک دیتابیس را تغییر داده و کدام‌یک فقط خوانده است، بدون بازرسی بدنه درخواست (Body) غیرممکن می‌شود.

 

ج) اشتراک‌گذاری لینک (Deep Linking)

  • مشکل: شما نمی‌توانید نتیجه یک درخواست POST را بوک‌مارک کنید یا لینک آن را برای کسی بفرستید. اگر جستجوی کاربر با POST انجام شود، URL مرورگر تغییر نمی‌کند و کاربر نمی‌تواند لینک صفحه جستجو را برای دوستش بفرستد. پارامترها در Body مخفی هستند، نه در URL.

 

۵. چه زمانی استفاده از "فقط POST" توجیه‌پذیر است؟

با وجود معایب بالا، سناریوهایی وجود دارد که استفاده از POST برای Query در معماری CQRS منطقی و حتی لازم است:

 

۱. الگوهای جستجوی پیچیده (Complex Search Criteria)

گاهی اوقات فیلترهای جستجوی شما آنقدر پیچیده و زیاد هستند که تبدیل آن‌ها به Query String در متد GET باعث طولانی شدن بیش از حد URL می‌شود.

  • استاندارد HTTP محدودیتی برای طول URL ندارد، اما مرورگرها و سرورها (مثل IIS یا Nginx) معمولاً محدودیت‌هایی (مثلاً ۲۰۴۸ کاراکتر) دارند.

  • در این حالت، ارسال آبجکت فیلتر در بدنه (Body) یک درخواست POST (مثلاً به اندپوینت /products/search) یک الگوی رایج و پذیرفته شده است.

 

۲. امنیت داده‌های حساس در جستجو

اگر پارامترهای جستجو حاوی اطلاعات حساس باشند (مثلاً کد ملی یا اطلاعات مالی)، نباید آن‌ها را در URL قرار داد (چون URLها در History مرورگر و لاگ‌های شبکه ذخیره می‌شوند). در این حالت، استفاده از POST برای مخفی کردن پارامترها در Body الزامی است.

 

۳. معماری‌های مبتنی بر پیام (Message-Driven)

اگر معماری CQRS شما به گونه‌ای است که فرانت‌‌اند مستقیماً متدها را صدا نمی‌زند، بلکه "پیام" (Message) یا "Command/Query Objects" را به یک باس (Bus) ارسال می‌کند، استفاده از تک‌متد POST منطقی است.

مثال:

POST /api/dispatcher
{
  "type": "GetUserDetailsQuery",
  "payload": { "userId": 101 }
}

در اینجا شما عملاً پروتکل انتقال خود را روی HTTP سوار کرده‌اید.

 

۶. نتیجه‌گیری و توصیه معماری

در پاسخ به سوال شما: بله، در Ajax می‌توان فقط از POST استفاده کرد و این کار در فریم‌ورک‌های مدرن بسیار ساده است.

اما آیا باید این کار را بکنید؟

 

توصیه برای پروژه‌های استاندارد:

برای اکثر پروژه‌های وب، رعایت اصول REST در کنار CQRS بهترین تعادل را ایجاد می‌کند:

  • برای Commands (نوشتن): از POST، PUT، DELETE استفاده کنید.

  • برای Simple Queries (خواندن بر اساس ID یا لیست ساده): حتماً از GET استفاده کنید تا از مزایای کشینگ HTTP و قابلیت بوک‌مارک کردن بهره‌مند شوید.

  • برای Complex Queries (جستجوی پیشرفته): استفاده از POST به عنوان یک استثنا (مثلاً /search endpoints) کاملاً پذیرفته شده است.

 

توصیه برای پروژه‌های خاص (SPAهای پیچیده یا Enterprise):

اگر از ابزارهایی مثل GraphQL استفاده می‌کنید یا سیستم شما تماماً بر اساس ارسال پیام (Message-Based) طراحی شده است، معماری "فقط POST" مشکلی ایجاد نمی‌کند، به شرطی که:

  1. استراتژی Caching سمت کلاینت (Client-side caching) قدرتمندی داشته باشید.

  2. مستندات API دقیقی داشته باشید، زیرا متد HTTP دیگر راهنمای توسعه‌دهنده نیست.

 
لینک استاندارد شده: 5mL8n

0 نظر

    هنوز نظری برای این مقاله ثبت نشده است.
جستجوی مقاله و آموزش
دوره‌ها با تخفیفات ویژه