مذاکره محتوا در Web API
شناسه پست: 3853
بازدید: 793

مذاکره محتوا، فرآیند انتخاب بهترین منبع برای یک response در صورت در دسترس بودن چندین منبع میباشد. مذاکره محتوا یک ویژگی HTTP است که از قبل وجود داشته است، اما به هر دلیلی، شاید کمی کمتر از آن استفاده شده باشد.

به طور خلاصه، مذاکره محتوا به شما این امکان را می‌دهد که محتوایی را که می‌خواهید در پاسخ به درخواست REST API دریافت کنید را انتخاب کنید یا بهتره بگوییم «مذاکره کنید».

میتوانید سورس کد را از اینجا دانلود کنید.

چطور مذاکره محتوا کار میکند؟

مذاکره محتوا زمانی اتفاق می‌افتد که یک کلاینت، نوع رسانه‌ای که می‌خواهد را به عنوان response در Accept header درخواست تعیین کند. به طور پیش‌فرض، ASP.NET Core Web API یک نتیجه فرمت‌شده JSON را برمی‌گرداند و هدر Accept مرورگر را نادیده می‌گیرد.

ASP.NET Core به طور پیش فرض از انواع رسانه های زیر پشتیبانی می کند:

  • application/json
  • text/json
  • text/plain

برای امتحان کردن این، اجازه دهید یک پروژه Web API پیش‌فرض و یک مدل ساده برای BlogPost ایجاد کنیم:

و یک کلاس به نام Blog که تمام پست های blog را لیست می کند:

ما قصد داریم یک کنترلر به نام BlogController تنها با یک متد ()Get ایجاد کنیم که یک blog post و یک blog را دربر دارد و آنها را به عنوان نتیجه برمی گرداند:

مذاکره محتوا توسط ObjectResult و متد ()Ok که از OkObjectResult ارث بری کرده و خود OkObjectResult نیز از ObjectResult ارث بری میکند پیاده سازی میشود. این بدان معناست که متد controller ما می‌تواند response محتوای مذاکره شده را برگرداند.

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

ما نتیجه را با Ok() helper method برمی گردانیم که همیشه آبجکت و کد وضعیت 200 OK را برمی گرداند.

برگرداندن JSON Response پیشفرض

اگر هم اکنون برنامه خود را اجرا کنیم، هنگام اجرا در مرورگر به صورت پیش فرض پاسخ JSON دریافت خواهیم کرد:

به منظور تست صحیح response ها، از Postman استفاده می کنیم:

درخواست پیشفرض در postman

به وضوح می‌بینید که نتیجه پیش‌فرض هنگام فراخوانی GET در /api/blog، نتیجه JSON ما را برمی‌گرداند. آن دسته از کسانی که چشمان تیزبینی دارند حتی ممکن است متوجه شده باشند که ما از هدر Accept با application/xml استفاده کردیم تا سعی کنیم سرور را مجبور کنیم که انواع رسانه های دیگر مانند متن ساده و XML را برگرداند.

اما این کار نمی کند. چرا؟

زیرا ما باید formatter های سرور را پیکربندی کنیم تا response را آنطور که می‌خواهیم فرمت کند.

بیایید ببینیم چگونه باید این کار را انجام دهیم.

برگرداندن XML Response

یک سرور به صراحت مشخص نمی کند که در کجا response را به JSON قالب بندی می کند. اما می‌توانیم با تغییر گزینه‌های پیکربندی از طریق گزینه‌های متد ()AddControllers آن را override کنیم. به‌طور پیش‌فرض، می‌توان آن را در کلاس Program یافت و به شکل زیر است:

ما می‌توانیم گزینه‌های زیر را برای فعال کردن سرور برای قالب‌بندی XML response هنگامی که کلاینت سعی می‌کند برای آن مذاکره کند، اضافه کنیم:

اول از همه، ما باید به یک سرور بگوییم که برای هدر Accept احترام قائل شود. پس از آن، فقط متد ()AddXmlSerializerFormatters را برای پشتیبانی از فرمت‌کننده‌های XML اضافه می‌کنیم.

اکنون که سرور خود را پیکربندی کرده ایم، اجازه دهید یک بار دیگر مذاکره محتوا را آزمایش کنیم:

بیایید ببینیم اگر همان درخواست را از طریق Postman ارسال کنیم، اکنون چه اتفاقی می افتد:

درخواست xml در postman

میبینید که پاسخ XML ما اینجا وجود دارد، این پاسخ، دیگر یک پاسخ پیش فرض نیست. با تغییر هدر Accept می‌توانیم response هایی با قالب‌بندی متفاوت دریافت کنیم.

اما اگر با وجود این همه انعطاف، یک کلاینت، نوع رسانه ای را درخواست کند که سرور نداند چگونه آن را قالب بندی کند، تکلیف چه میشود؟

محدود کردن نوع رسانه ها در مذاکره محتوا

در حال حاضر، اگر نوع رسانه شناسایی نشود، پاسخ به طور پیش‌فرض JSON خواهد بود.

اما می توانیم این رفتار را با افزودن یک خط به configuration محدود کنیم:

ما گزینه ReturnHttpNotAcceptable = true را اضافه کرده‌ایم که به سرور می‌گوید اگر کلاینت سعی کند برای نوع رسانه‌ای که سرور پشتیبانی نمی‌کند مذاکره کند، باید کد وضعیت 406 Not Acceptable را برگرداند.

این اپلیکیشن شما را محدودتر می کند و استفاده کننده API را مجبور می کند فقط انواعی را که سرور پشتیبانی می کند را درخواست کند. کد وضعیت 406 برای این منظور ایجاد شده است. می‌توانید جزئیات بیشتری در مورد آن در مقاله مرجع HTTP ما بیابید، یا اگر می‌خواهید حتی در آن عمیق‌تر شوید، می‌توانید RFC2616 را بررسی کنید.

اکنون، بیایید نوع رسانه text/css را با استفاده از Postman واکشی کنیم تا ببینیم چه اتفاقی می‌افتد:

درخواست css در postman

و همانطور که انتظار می رود، هیچ response body وجود ندارد، و تنها چیزی که به دست می آوریم یک کد وضعیت 406 Not Acceptable است.

Formatter های سفارشی در ASP.NET Core

بیایید تصور کنیم که در حال ساخت یک REST API عمومی هستیم و باید از مذاکره محتوا برای نوعی که «در چارچوب» نیست پشتیبانی کند.

ASP.NET Core از ایجاد formatter های سفارشی پشتیبانی می‌کند. هدف آنها این است که به شما انعطاف‌پذیری لازم برای ایجاد formatter خود برای هر نوع رسانه‌ای که نیاز به پشتیبانی دارید را بدهد.

با استفاده از روش زیر می‌توانیم formatter سفارشی را بسازیم:

  • یک کلاس output formatter ایجاد کنید که کلاس TextOutputFormatter را به ارث ببرد
  • یک کلاس input formatter ایجاد کنید که کلاس TextInputformatter را به ارث ببرد
  • کلاس‌های input و output را به collection های InputFormatters و OutputFormatters به همان روشی که برای قالب‌کننده XML انجام دادیم اضافه کنید.

بیایید یک CSV output formatter سفارشی را برای مثال خود پیاده‌سازی کنیم.

پیاده سازی یک Formatter سفارشی در ASP.NET Core

از آنجایی که ما در این مقاله فقط به قالب بندی response ها علاقه مندیم، باید فقط یک output formatter پیاده سازی کنیم. ما فقط در صورتی به input formatter نیاز خواهیم داشت که request body حاوی نوع مربوطه باشد.

ایده این است که یک response را برای برگرداندن لیست بلاگ ها و لیست متناظر پست های بلاگ در قالب CSV قالب بندی کنیم.

بیایید یک کلاس CsvOutputFormatter به پروژه خود اضافه کنیم:

در اینجا چند نکته قابل توجه است.

در سازنده، ما تعریف کرده ایم که این formatter باید کدام نوع media و همچنین encoding ها را تجزیه کند.

متد override ،CanWriteType شده است و نشان می دهد که آیا می توان نوع Blog را توسط این serializer نوشت یا خیر. متد WriteResponseBodyAsync پاسخ را می سازد. و در نهایت، ما متد FormatCsv را داریم که یک response را آنطور که ما می خواهیم قالب بندی می کند.

پیاده سازی کلاس بسیار ساده است و اصلی ترین چیزی که باید روی آن تمرکز کنید منطق متد FormatCsv است.

اکنون، فقط باید CsvOutputFormatter جدید ساخته شده را به لیست OutputFormatters در متد ()AddMvcOptions اضافه کنیم:

حالا بیایید این را اجرا کنیم و ببینیم آیا واقعاً کار می کند یا خیر. این بار application/csv را به عنوان مقدار هدر Accept در درخواست Postman قرار می دهیم:

درخواست csv در postman

کار می کند، فقط اینکه ورودی ما به عنوان یک CSV response قالب بندی شده است.

اگر می خواهید در مورد آنها بیشتر بدانید، یک صفحه عالی در مورد formatter های سفارشی در ASP.NET Core وجود دارد.

نتیجه گیری

در این پست وبلاگ، ما از طریق پیاده سازی دقیق، مکانیسم مذاکره محتوا در یک پروژه ASP.NET Core را بررسی کردیم. ما در مورد formatter ها و نحوه ساخت یک قالب سفارشی و همچنین نحوه تنظیم آنها در پیکربندی پروژه خود یاد گرفتیم.

ما همچنین یاد گرفتیم که چگونه یک برنامه را فقط به انواع خاصی از محتوا محدود کنیم و دیگر نوع ها را نپذیریم.

نویسنده

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