به مدت شانزده سال، توسعه‌دهندگانی که نیاز داشتند پرسش‌های پیچیده‌ای از یک سرور بپرسند، با یک راهکار موقت دست‌وپنجه نرم می‌کردند. وقتی حجم پیلود (payload) یک جستجو برای یک URL بیش از حد بزرگ می‌شد، یا زمانی که فیلترهای تو در تو و پارامترهای حساس در یک رشته پرس‌وجو (query string) نمی‌گنجیدند، تنها گزینه عملی استفاده از POST بود. این متد بایت‌ها را منتقل می‌کرد، اما در مورد هدف عملیات دروغ می‌گفت. POST نشان‌دهنده تغییر وضعیت است. استفاده از آن برای یک عملیات فقط-خواندنی، کل مسیر شبکه — از کش‌ها و پروکسی‌ها گرفته تا مرورگرها — را مجبور می‌کرد تا با یک جستجوی بی‌گناه، طوری برخورد کنند که انگار قرار است پایگاه داده را تغییر دهد.

آن سازش بالاخره پایان یافت. در ژوئن ۲۰۲۶، IETF استاندارد RFC 10008 را منتشر کرد که به طور رسمی متد QUERY را استانداردسازی می‌کند. این اولین متد جدید HTTP از زمان معرفی PATCH در سال ۲۰۱۰ است. QUERY مشخصاً برای درخواست‌های ایمن و ایدم‌پوتنت (idempotent) که نیاز به بدنه (body) دارند، ایجاد شده است. این متد وضعیت سرور را تغییر نمی‌دهد. تکرار همان درخواست، نتیجه یکسانی تولید می‌کند. این متد قابلیت کش شدن (cacheable) دارد، به این معنی که واسطه‌ها می‌توانند پاسخ را ذخیره و دوباره استفاده کنند. و برخلاف GET، مانند POST اجازه ارسال پیلود داده را می‌دهد.

پرس‌وجوهای GraphQL و نقاط پایانی (endpoints) پیچیده جستجوی REST بزرگترین برندگان این تغییر هستند. دیگر مجبور نیستید شصت پارامتر پرس‌وجو را در یک URL بچپانید یا یک سند فیلتر JSON را درون بدنه یک درخواست POST پنهان کنید که واسطه‌ها از کش کردن آن خودداری می‌کنند. اکنون معناشناسی (semantics) عملیات صادقانه است.

اما یک RFC فقط روی کاغذ است. بین اپلیکیشن شما و کاربران شما، لایه ضخیمی از زیرساخت قرار دارد که بیشتر آن‌ها حتی نام QUERY را هم نشنیده‌اند.

مشکل کش شدن هنوز حل نشده است

در یک درخواست GET، کش کردن ساده است. کلید کش همان URI است. دو کاربر که به یک URL مشابه مراجعه می‌کنند، با فرض اینکه هدرها اجازه دهند، پاسخ ذخیره‌شده یکسانی دریافت می‌کنند.

QUERY این مدل را می‌شکند، زیرا پارامترهای درخواست در بدنه قرار دارند. برای اینکه یک کش تشخیص دهد که دو درخواست یکسان هستند، کلید کش باید هم URI و هم محتوای بدنه را شامل شود. این الزام، اصطکاک عملیاتی واقعی ایجاد می‌کند.

اول اینکه، سرورهای لبه (edge servers) و CDNها باید کل بدنه درخواست را قبل از محاسبه هش (hash) بافر کنند. این کار در گره لبه (edge node)، حافظه و زمان می‌برد. دوم اینکه، دو پرس‌وجوی منطقاً یکسان ممکن است بایت‌های متفاوتی تولید کنند. یک کلاینت ممکن است {"status":"active"} ارسال کند، در حالی که کلاینت دیگری {"status": "active"} را با فاصله‌گذاری یا ترتیب کلیدهای متفاوت ارسال کند. مگر اینکه لایه کش، بدنه را تجزیه (parse)، نرمال‌سازی و استانداردسازی (canonicalize) کند — یعنی کلیدهای JSON را مرتب کند، قالب‌بندی‌های بی‌اهمیت را حذف کند و تفاوت‌های کدگذاری را مدیریت کند — در غیر این صورت، همان پرس‌وجو هر بار از کش عبور خواهد کرد (cache miss).

از همه مهم‌تر اینکه، CDNهای جریان اصلی هنوز کش را بر اساس بدنه درخواست برای QUERY تقسیم‌بندی نمی‌کنند. برای مثال، Cloudflare در شکل فعلی خود، با بدنه به عنوان بخشی از کلید کش برای این متد برخورد نمی‌کند. اگر QUERY را با این فرض پیاده‌سازی کنید که «قابلیت کش شدن» به معنای «کش شدن» است، ممکن است با خطاهای برخورد (collision errors)، عدم برخورد کلی با کش (universal cache misses) یا پاسخ‌هایی مواجه شوید که بین درخواست‌های بی‌ربط نشت می‌کنند. تا زمانی که ارائه‌دهنده شما پشتیبانی صریح از آن را اعلام نکند، فرض کنید QUERY در محیط عملیاتی (production) به طور معناداری قابلیت کش شدن ندارد.

ابزارهای شما احتمالاً ابتدا آن را مسدود می‌کنند

هر درخواست HTTP از مجموعه‌ای از میان‌افزارها (middleboxes) عبور می‌کند و اکثر آن‌ها قوانین سخت‌گیرانه‌ای درباره اینکه کدام متدها مجاز هستند، اعمال می‌کنند.

فایروال‌های اپلیکیشن وب (WAF) و درگاه‌های API اغلب بر لیست‌های مجاز (allowlists) صریح تکیه می‌کنند. یک مجموعه قوانین معمولی، متدهای GET، POST، PUT، DELETE و PATCH را مجاز می‌داند. هر چیز دیگری حذف شده یا با خطای 405 Method Not Allowed پاسخ داده می‌شود. QUERY قبل از اینکه حتی به کد اپلیکیشن شما برسد، با این دیوارها برخورد خواهد کرد.

موتورهای قوانین امنیتی مانع دیگری ایجاد می‌کنند. برخی از سیستم‌های تشخیص نفوذ فرض می‌کنند که درخواستی که حاوی بدنه است