شما از کدهای وضعیت HTTP اشتباه استفاده می کنید – در اینجا راه حل – جامعه dev

سوال:
چگونه می توانید یک کد وضعیت را برای سفارش انتخاب کنید که قابل پردازش نباشد زیرا آدرس حمل و نقل مشتری خارج از منطقه تحویل است؟
این که آیا شما در تلاش برای یافتن کد وضعیت مناسب هستید ، یا اینکه کد وضعیت خاصی برای استفاده دارید ، این وبلاگ برای شما مناسب است.
کد وضعیت HTTP چیست و چرا باید اهمیت دهید
کد وضعیت محبوب است
حتی اگر شما یک پسر فنی نیستید ، بسیار دوست دارید که این شماره ها را شنیده اید 404
با 502
بشر این امر به این دلیل است که کد وضعیت HTTP آنقدر محبوب است که به معنای واقعی کلمه در همه جای اینترنت است.
کدهای وضعیت HTTP مدتهاست که سنگ بنای خطای خطای برنامه وب بوده است. این کدها در RFC 7231 تعریف شده است ، این کدها به عنوان روشی استاندارد برای سرورها برای برقراری ارتباط نتیجه یک درخواست به مشتری عمل می کنند.
استاندارد چندین دسته از کدهای وضعیت را تعریف می کند ، مانند 2xx
برای موفقیت ، 4xx
برای خطاهای مشتری ، و 5xx
برای خطاهای سرور
نقل قول از RFC 7231:
مشتریان HTTP لازم نیست
معنای همه کدهای وضعیت ثبت شده را درک کنید ، هر چند چنین
درک آشکارا مطلوب است. با این حال ، مشتری باید
کلاس هر کد وضعیت را درک کنید ، همانطور که در اولی نشان داده شده است
رقم ، و با یک کد وضعیت ناشناخته به عنوان معادل آن رفتار کنید
کد وضعیت X00 آن کلاس
این به یک اجماع صنعتی تبدیل شده است تا این کدهای وضعیت را به عنوان راهی برای تعیین سریع درخواست موفقیت یا ناموفق ، بررسی کند. به عنوان مثال ، بسیاری از کتابخانه ها و چارچوب ها در صورت ایجاد درخواست به وضعیت خطا ، استثنائی را مطرح می کنند. در اینجا یک مثال ساده با استفاده از پایتون آورده شده است requests
کتابخانه:
import requests
response = requests.get("https://api.example.com/data")
response.raise_for_status() # this would raise exception when status code > 400
print("Data retrieved successfully!")
در این مثال ،
raise_for_status()
به طور خودکار یکHTTPError
اگر سرور کد وضعیت 4xx یا 5xx را برگرداند. این یک الگوی متداول در بسیاری از برنامه ها است تا اطمینان حاصل شود که فقط درخواست های موفق بیشتر پردازش می شوند.
چرا انتخاب کد وضعیت برای خطای اتوبوس خود دشوار است
استفاده از آن معمول است (اما لزوماً صحیح نیست) 4xx
کدهای مانند 400 Bad Request
یا 403 Forbidden
وقتی چیزی پیش می رود. به عنوان مثال ، یک کاربر “حق بیمه” که در تلاش برای دسترسی به یک ویژگی موجود فقط برای کاربران “Pro” ممکن است برگردد 403 Forbidden
وضعیت در چنین مواردی ، خطا مشخص است و کد وضعیت به خوبی به سناریو می پردازد.
اما با افزایش برنامه های وب در پیچیدگی و مقابله با قوانین ظریف تر تجارت ، همه چیز پیچیده تر می شود. سناریویی را در نظر بگیرید که در آن به دلیل عدم تطابق بین آدرس حمل و نقل مشتری و منطقه تحویل ، یک دستور قابل پردازش نیستبشر چگونه باید این مسئله از نظر کدهای وضعیت HTTP نشان داده شود؟
پاسخی آسان یا واضح وجود ندارد. در حالی که ما می توانیم استفاده کنیم 400 Bad Request
، این نقض قانون تجاری خاص را که اتفاق می افتد کاملاً ضبط نمی کند. به همین ترتیب ، الف 409 Conflict
می تواند در بعضی موارد کار کند ، اما هنوز به اندازه کافی دقیق نیست. با افزایش تعداد مسائل بالقوه – خواه مربوط به خرابی های پرداخت ، عدم تطابق یا درگیری منابع باشد – آشکارتر می شود که کدهای وضعیت HTTP برای رسیدگی به پیچیدگی کامل منطق کسب و کار مدرن ساخته نمی شوند.
نغمه
در حال حاضر ، چند روش وجود دارد که صنعت با مشکل رسیدگی به خطاهای منطق تجارت در برنامه های وب سروکار دارد. این راه حل ها به دلیل محدودیت کدهای وضعیت HTTP ، اغلب شامل راه حل ها یا تعمیم ها هستند. در اینجا برخی از رویکردهای متداول:
- تعبیه وضعیت سفارشی در بدن درخواست
یک رویکرد همیشه بازگشت a 200 OK
کد وضعیت ، حتی در صورت عدم موفقیت درخواست ، و یک کد وضعیت سفارشی را در بدنه پاسخ قرار دهید. این روش شامل بازگشت کد خطای خاص در تجارت به همراه جزئیات بیشتر است.
نمونه:
{
"business_code": "CUSTOMIZED_BUSINESS_ERROR",
"detail": "The shipping address is outside the serviceable delivery zone."
}
من شخصاً در طول حرفه خود چندین بار با این راه حل روبرو شده ام. هنگامی که سیستم فقط چند مؤلفه را در اختیار دارد و با مستندات دقیق ، می تواند کار کند ، اما با افزایش سیستم و اجزای اضافی (مانند پراکسی ها ، دروازه های API و سیستم های ورود به سیستم) اضافه می شود ، این باعث می شود مشکلات جدیدی ایجاد کنید که لازم نیست در غیر این صورت حل کنید.
- به عنوان مثال ، 6xx به معنای برخی از قوانین تجاری ، 700 به معنای دیگران و غیره است.
برخی از راه حل ها سعی می کنند مجموعه ای از کدهای وضعیت خود را فراتر از استاندارد تعریف کنند 2xx
با 4xx
وت 5xx
دسته بندی ها به عنوان مثال ، 6xx
ممکن است قوانین تجاری را با کدهای خاص برای هر سناریو نشان دهد (به عنوان مثال ، 700
برای برخی از منطق تجاری دیگر). در حالی که این امر از خواندن بدنه درخواست برای تعیین خرابی جلوگیری می کند ، استانداردهای HTTP را نقض می کند ، به این معنی که بسیاری از ابزارها ممکن است خطاها را به وجود آورند یا از این کدها پشتیبانی نکنند.
نمونه:
600: CONNECTION ERROR - This indicates a general connection error
601: INCOMPLETE ERROR - This indicates sever sends an incomplete page/object (as indicated by Content-Length header)
701: ERROR TEXT FOUND - This code is returned if any error text (such as, "Service Unavailable") are found in the main page (frame HTML contents included). Note that the error text must be defined in advance of the test. Error text means if the text is found, this session should be considered a failure.
با توجه به RFC 7231 ،
کدهای وضعیت جدید لازم است که تحت یکی از دسته ها قرار بگیرند
تعریف شده در بخش 6.
کدهای وضعیت> = 600 نامعتبر هستند زیرا در خارج از دسته های تعریف شده قرار نمی گیرند.
از
- کد وضعیت 4xx + پیام خطای عمومی
{
"status": 400,
"message": "Something went wrong"
}
بازگشت مشترک این است که برگرداندن 4xx
کد وضعیت (به طور معمول 400 Bad Request
) و شامل یک پیام خطای عمومی مانند “چیزی که اشتباه شد” در بدن پاسخ است. این رویکرد علت واقعی عدم موفقیت منطق کسب و کار را پنهان می کند و تمام خطاهای مشتری را در یک دسته مبهم قرار می دهد. اگرچه این ممکن است برای برنامه های کوچک یا نمونه های اولیه در مقیاس کوچک کافی باشد ، با افزایش پیچیدگی قوانین تجاری ، به سرعت ناکافی می شود.
برخی از سیستم ها با بازگرداندن یک عبارت دلیل یک خط یا یک پیام کمی گسترده ، یک قدم جلوتر می روند ، اما هنوز هم از انتقال جزئیات خطای ساختاری و عملی به مشتریان کم نمی شوند.
- با استفاده از همان کد وضعیت برای چندین مسئله منطق کسب و کار
{
"status": 400,
"message": "Payment failed"
}
{
"status": 400,
"message": "Invalid shipping address"
}
با افزایش خطاهای منطق کسب و کار در تعداد و تنوع ، برخی از تیم ها سعی می کنند آنها را در مجموعه محدودی از کدهای وضعیت موجود قرار دهند. به عنوان مثال ، هر دو عدم پرداخت پرداخت به دلیل بودجه کافی و عدم تطابق در آدرس حمل و نقل ممکن است بازگردانده شود 400 Bad Request
بشر در حالی که این رویکرد کار با سمت سرور را ساده می کند ، وضوح پیام های خطا را به شدت محدود می کند ، و تفاوت بین انواع مختلف خرابی های تجاری را برای مشتریان دشوار می کند. این همچنین بار غیر ضروری را برای توسعه دهندگان طرف مشتری قرار می دهد تا مهندس معکوس ماهیت واقعی خطا از پاسخ های مبهم را معکوس کنند.
بهترین تمرین
پیام خطای ساختاری + مستندات (با رعایت استانداردها)
یک رویکرد متفکرانه در مورد نقض قانون تجارت ، بازگشت مناسب است 4xx
کد وضعیت – ایده آل که از نظر معنایی با خطا مطابقت دارد (برای مثال ، 407 Proxy Authentication Required
، در صورت وجود) – برای نشان دادن این درخواست به دلیل محدودیت تجاری ناموفق بود.
علاوه بر این ، بدن پاسخ می تواند شامل a باشد پیام خطای ساختاری بر اساس RFC 9457 (جزئیات مشکل برای API HTTP) ، که زمینه هایی مانند type
با title
با status
با detail
وت instance
بشر این قالب وضوح و قوام را تشویق می کند ، و درک ، رسیدگی و ردیابی خطاها را برای توسعه دهندگان و سیستم های خودکار آسان تر می کند.
به همان اندازه مهم داشتن هر نوع خطا است به وضوح مستند شده است بنابراین توسعه دهندگان مشتری می دانند که خطایی به چه معنی است و چگونه می توان آن را پرداخت کرد. مستندات خوب و خوب ، تجارب ثروتمندتر مشتری را قادر می سازد ، حدس و گمان را کاهش می دهد و به جلوگیری از بروز مشکلات قبل از بروز آنها کمک می کند.
Stripe با مستندات اختصاصی کد خطای خود ، یک کار عالی در این زمینه انجام می دهد ، که توضیحات مفصلی را برای طیف گسترده ای از خطاهای مربوط به تجارت ارائه می دهد. تعهد آنها به شفافیت و تجربه توسعه دهنده مشهود و ستودنی است.
گفته می شود ، چند زمینه وجود دارد که پیشرفت های بیشتر می تواند تجربه را حتی بیشتر تقویت کند:
- فرمت خطای ساختاری آنها ، در حالی که واضح است ، به صراحت از RFC 9457 پیروی نمی کند ، و زمینه ها را از دست می دهد
instance
این می تواند برای اشکال زدایی ارزشمند باشد. - هنوز مشخص نیست که آیا مستندات آنها به طور خودکار تولید می شود یا به صورت دستی نگهداری می شود. اگر این دومی باشد ، این می تواند چالش هایی را برای به روز نگه داشتن آن با API های در حال تحول ایجاد کند.
چگونه لیل این مشکل را حل می کند
پیام های خطای ساختاری + مستندات ایجاد شده به صورت خودکار
lihil
با ایجاد خطای ساختار یافته در کلاس اول ، مشکل را برطرف می کند. شما می توانید استثنائات غنی و ایمن را با زیر طبقه بندی اعلام کنید HTTPException[T]
، کجا T
ساختار خطا را تعریف می کند detail
میدان این استثنائات می توانند با استفاده از نقاط پایانی به طور مستقیم وصل شوند errors=
پارامتر این نه تنها پاسخهای خطای مداوم را تضمین می کند بلکه امکان پذیر است lihil
برای تولید خودکار مستندات OpenAPI برای هر خطای اعلام شده – از جمله پیوندی به یک صفحه مشکل دقیق در زیر برگه “مستندات خارجی”.
چگونه یک استثناء ساختاری را در لیل تعریف می کنید
from lihil import Empty, Lihil, Resp, Route, status, Meta
from lihil.interface import Base
from lihil.problems import HTTPException
class AddressOutOfScopeProblem(Base):
current_address: Annotated[str, Meta(examples=["home"])]
service_radius: Annotated[float, Meta(examples=[3.5])]
distance: Annotated[float, Meta(examples=4)]
message: str = ""
def __post_init__(self):
self.message = f"Your current address {self.current_address} is {self.distance} miles away and our service radius is {self.service_radius}"
class InvalidOrderError(HTTPException[AddressOutOfScopeProblem]):
"Address out of service zone"
__status__ = 422
instance: Annotated[str, Meta(examples=["2cd20e0c-9ddc-4fdc-8f61-b32f62ac784d"])]
detail: AddressOutOfScopeProblem
orders = Route("orders")
@orders.post(errors=[InvalidOrderError])
async def create_orders() -> Resp[Empty, status.CREATED]: ...
lhl = Lihil(routes=[orders])
if __name__ == "__main__":
lhl.run(__file__)
کد فوق را اجرا کنید و به طور خودکار در OpenAPI شما ثبت می شود.
چه چیزی آن را خوب می کند
همانطور که از OpenAPI می بینید ، هر یک از این پاسخ خطا از فرمت RFC 9457 ، از جمله زمینه هایی مانند type
با title
با status
با detail
وت instance
بشر شما می توانید نحوه ارسال خطاها را با ثبت نام دستی ها تنظیم کنید @problem_solver
، که استثنائات خاص یا کدهای وضعیت را به پاسخ های ساختاری ترسیم می کند. دستگیرندگان استثناء خاص بر روی موارد مبتنی بر وضعیت ، برتری دارند و به شما کنترل ریز و درشت می دهند.
به طور پیش فرض ، lihil
همچنین پاسخ های مفصلی را برای موضوعات مشترک مانند پارامترهای گمشده ، بازگرداندن پاسخ 422 ساختار یافته برای InvalidRequestErrors
-با اطلاعات سطح فیلد کاملاً مناسب است. این پاسخ ها نه تنها قابل خواندن با دستگاه هستند بلکه کاملاً از جعبه مستند هستند.
از همه مهمتر ، همه این اسناد به طور خودکار با کد شما همگام سازی می شوند. نیازی به به روزرسانی دستی یا حفظ مرجع کد خطای جداگانه نیست. lihil
رفتار و مستندات API خود را در تراز کامل نگه می دارد.