درخواست‌های شرطی و ETag در گیت هاب (Conditional Requests and ETag) یکی از مباحث کلیدی برای توسعه‌دهندگانی است که با API گیت هاب کار می‌کنند یا ابزارهایی می‌سازند که به‌طور مرتب داده‌ها را از این پلتفرم دریافت می‌کنند. هر درخواست به API گیت هاب، سهمی از سقف نرخ (Rate Limit) را مصرف می‌کند؛ استفاده‌ی نادرست از این API می‌تواند به سرعت به اتمام سقف منجر شود. درخواست‌های شرطی، راهکاری استاندارد بر پایه‌ی پروتکل HTTP (Hypertext Transfer Protocol) است که با ارسال هدر If-None-Match و استفاده از ETag (Entity Tag)، از انتقال داده‌های تکراری جلوگیری می‌کند. اگر با مبانی REST آشنا نیستید، مطالعه‌ی REST API و اصول آن نقطه‌ی شروع مناسبی است. در این نوشتار، از مبانی هدرهای HTTP تا پیاده‌سازی عملی در کلاینت‌های مختلف و تأثیر آن بر سقف نرخ، مسیر کامل را با تمرکز بر مهندسی ترسیم می‌کنم.

مبانی کش در HTTP

پروتکل HTTP از ابتدا با هدف صرفه‌جویی در پهنای باند طراحی شده است. کش (Caching) در این پروتکل، دو سطح دارد:

  • کش محلی: کلاینت نسخه‌ای از پاسخ را ذخیره می‌کند و در درخواست‌های بعدی، از آن استفاده می‌کند.
  • کش شرطی: کلاینت از سرور می‌پرسد که آیا نسخه‌ی محلی هنوز معتبر است یا خیر.

در کش شرطی، اگر نسخه‌ی محلی معتبر باشد، سرور پاسخ 304 Not Modified می‌فرستد، بدون محتوا؛ و همین، پهنای باند را صرفه‌جویی می‌کند. اگر معتبر نباشد، پاسخ کامل با محتوای جدید ارسال می‌شود. اگر با مفاهیم کد وضعیت HTTP آشنایی ندارید، مطالعه‌ی رفع خطای ۴۰۴ نمونه‌ای از این کدها را نشان می‌دهد.

ETag چیست و چگونه ساخته می‌شود

ETag یک هدر پاسخ HTTP است که نماینده‌ی نسخه‌ی خاصی از یک منبع است. سرور این هدر را با پاسخ می‌فرستد و کلاینت می‌تواند در درخواست‌های بعدی، آن را با هدر If-None-Match ارسال کند. دو شکل اصلی ETag وجود دارد:

  • ETag قوی: نشان‌دهنده‌ی نسخه‌ی بایت‌به‌بایت منبع است.
  • ETag ضعیف: با پیشوند W/ مشخص می‌شود و نشان می‌دهد که منبع از نظر معنایی معتبر است، اما ممکن است از نظر بایت تفاوت داشته باشد.

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

درخواست شرطی چیست

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

  • If-None-Match: اگر ETag منبع با مقدار ارسالی یکسان نباشد، پاسخ کامل ارسال می‌شود.
  • If-Modified-Since: اگر منبع از تاریخ مشخصی تغییر نکرده باشد، پاسخ 304 ارسال می‌شود.

در گیت هاب، ترکیب این دو هدر، امکان مدیریت کارآمد کش را فراهم می‌کند. برای مثال، اگر ابزاری روزانه وضعیت یک مخزن را بررسی می‌کند، می‌تواند با ارسال ETag قبلی، فقط در صورت تغییر داده، پاسخ کامل دریافت کند.

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

سقف نرخ در گیت هاب

گیت هاب برای API عمومی خود، سقف نرخ مشخصی تعیین کرده است:

  • کاربران بدون توکن: ۶۰ درخواست در ساعت به‌ازای هر IP.
  • کاربران با توکن شخصی: ۵۰۰۰ درخواست در ساعت.
  • اپلیکیشن‌های GitHub App: سقف‌های اختصاصی بر پایه‌ی نصب.

درخواست‌های شرطی که پاسخ 304 می‌گیرند، از سقف نرخ کسر نمی‌شوند. همین ویژگی، درخواست‌های شرطی را به یکی از مهم‌ترین ابزارهای بهینه‌سازی تبدیل می‌کند. اگر با معماری API و محدودیت‌های آن آشنایی ندارید، مطالعه‌ی بهینه‌سازی عملکرد REST API کمک‌کننده است.

هدرهای گیت هاب

گیت هاب در پاسخ‌های خود چند هدر کلیدی ارسال می‌کند:

هدرمعناکاربرد
ETagشناسه نسخه منبعدرخواست شرطی بعدی
Last-Modifiedآخرین زمان تغییرIf-Modified-Since
X-RateLimit-Limitسقف کل نرخپایش مصرف
X-RateLimit-Remainingسقف باقی‌ماندهمدیریت فراخوانی
X-RateLimit-Resetزمان بازنشانی سقفزمان‌بندی درخواست‌ها

پایش این هدرها، به‌ویژه در ابزارهای خودکار، بسیار مهم است. نادیده گرفتن سقف نرخ می‌تواند به قطع دسترسی موقت منجر شود.

پیاده‌سازی در کلاینت

پیاده‌سازی درخواست شرطی در کلاینت، در ساده‌ترین شکل، به این شکل است:

curl -H "If-None-Match: "ETAG_VALUE"" https://api.github.com/repos/owner/repo

پاسخ سرور، در صورت معتبر بودن ETag، کد 304 Not Modified با بدنه‌ی خالی خواهد بود. اگر ETag تغییر کرده باشد، پاسخ کامل با محتوای جدید ارسال می‌شود.

در زبان‌های برنامه‌نویسی مانند Python، می‌توان این فرایند را با کتابخانه‌ی requests به‌سادگی پیاده‌سازی کرد:

import requests

headers = {'If-None-Match': previous_etag}
response = requests.get(url, headers=headers)

if response.status_code == 304:
    print("No change")
else:
    new_etag = response.headers.get('ETag')
    print("Updated")

نکته: ذخیره‌ی ETag در دیتابیس یا فایل، بخشی ضروری از این فرایند است. اگر با اصول مدیریت دیتابیس آشنایی ندارید، مطالعه‌ی کوئری‌های حرفه‌ای SQL کمک‌کننده است.

ETag ضعیف و قوی

گیت هاب معمولاً ETag قوی ارسال می‌کند، اما برخی نقاط پایانی (Endpoints) ممکن است ETag ضعیف ارسال کنند. تفاوت این دو:

  • ETag قوی: تضمین می‌کند که منبع بایت‌به‌بایت یکسان است.
  • ETag ضعیف: تنها تضمین می‌کند که منبع از نظر معنایی یکسان است؛ ممکن است در سطح بایت تفاوت‌های جزئی وجود داشته باشد.

در پیاده‌سازی، توجه به این تفاوت می‌تواند از خطاهای ظریف جلوگیری کند. اگر با اصول امضای دیجیتال و هش آشنا نیستید، مطالعه‌ی SSL و امنیت وب کمک‌کننده است.

خودکارسازی با اسکریپت

در ابزارهای خودکار مانند GitHub Actions، استفاده از درخواست‌های شرطی می‌تواند به کاهش هزینه و بهبود کارایی منجر شود:

name: Check Repo Changes
on:
  schedule:
    - cron: '0 */6 * * *'
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - name: Get ETag
        run: |
          ETAG=$(curl -sI https://api.github.com/repos/owner/repo | grep -i etag | awk '{print $2}')
          echo "ETAG=$ETAG" >> $GITHUB_ENV
      - name: Conditional Request
        run: |
          curl -H "If-None-Match: $ETAG" -o response.json -w "%{http_code}" https://api.github.com/repos/owner/repo

این ساختار، در ابزارهایی که به‌طور مرتب وضعیت مخازن را بررسی می‌کنند، بسیار کاربردی است. برای مطالعه‌ی بیشتر در این حوزه، GitHub Actions و خودکارسازی و راهنمای Pull Request منابع کاربردی محسوب می‌شوند.

خطاهای رایج

سه خطای رایج در استفاده از درخواست‌های شرطی:

  1. ذخیره‌ی نادرست ETag: ذخیره در محلی که به‌درستی مدیریت نمی‌شود، منجر به ارسال ETag اشتباه می‌گردد.
  2. نادیده گرفتن هدرهای سقف نرخ: عدم پایش X-RateLimit-Remaining می‌تواند به قطع دسترسی منجر شود.
  3. استفاده‌ی نادرست از If-Modified-Since: این هدر در مقایسه با ETag، دقت کمتری دارد و نباید به‌جای آن استفاده شود.

اگر با خطاهای مشابه در پروژه‌های خود مواجه شده‌اید، مطالعه‌ی رفع خطاهای رایج گیت کمک‌کننده است.

پرسش‌های پرتکرار

آیا درخواست‌های شرطی از سقف نرخ کسر می‌شوند؟

خیر، پاسخ‌های 304 از سقف نرخ کسر نمی‌شوند. همین ویژگی، آن‌ها را به ابزاری مؤثر برای بهینه‌سازی تبدیل می‌کند.

چگونه ETag را ذخیره کنیم؟

در یک پایگاه داده، فایل یا حافظه‌ی موقت، به شکلی که در درخواست بعدی قابل بازیابی باشد. بهترین شیوه، ذخیره‌ی ETag همراه با شناسه‌ی منبع در یک ساختار داده‌ی منظم است.

تفاوت ETag و Last-Modified چیست؟

ETag بر پایه‌ی محتوای منبع ساخته می‌شود و دقت بالاتری دارد؛ Last-Modified بر پایه‌ی زمان تغییر. برای سناریوهای دقیق، ETag انتخاب بهتری است.

کارایی که از پروتکل می‌آید

درخواست‌های شرطی و ETag در گیت هاب، نمونه‌ای روشن از این حقیقت است که بهینه‌سازی، پیش از هر ابزار یا کتابخانه، در سطح پروتکل نهفته است. با استفاده‌ی درست از هدرهای HTTP، می‌توان هم پهنای باند را صرفه‌جویی کرد و هم سقف نرخ را مدیریت نمود. برای تیم‌هایی که ابزارهای خودکار می‌سازند یا با API گیت هاب در مقیاس بالا کار می‌کنند، تسلط بر این مفاهیم یک سرمایه‌گذاری ضروری است. اگر در پروژه‌های واقعی با محدودیت‌های سقف نرخ یا پهنای باند مواجه شده‌اید، برای خوانندگان بعدی ارزشمند است بدانید کدام رویکرد بیشترین کمک را به شما کرده است.