• 0 رای - 0 میانگین
  • 1
  • 2
  • 3
  • 4
  • 5
نکات و ابهاماتی درمورد کاربرد متدهای GET و POST - متدهای Idempotent و غیر Idempotent
#1
این مورد نسبتا جالبی هست که بنظرم بیشتر یا حداقل خیلی از افراد نمیدونن.
میدونید که پروتکل HTTP متدهای مختلفی داره که متداول ترین اونا که توسعه دهندگان وب باهاشون سروکار دارن، متدهای GET و POST هستن.
متد GET همون متدی هست که موقع فراخوانی مستقیم آدرسها اجرا میشه. مثلا موقعی که روی یک لینک کلیک میکنید. در این روش تمام متغییرها، درصورت وجود، در URL ارسال میشن.
متد POST متدی هست که برای ارسال فرمها استفاده میشه. در این روش تمام متغییرهای فرم در بدنهء درخواست HTTP ارسال میشن و در URL وجود ندارن و دیده نمیشن. البته URL ای که یک درخواست POST بهش ارسال میشه میتونه شامل پارامترهای URL هم باشه که به اینصورت میشه گفت اطلاعات دیگه ای رو هم (البته معمولا بصورت ثابت و hard-code شده) در URL مشخص و ارسال کردیم، اما متد استفاده شده بهرحال POST هست و نه GET، چون درخواست HTTP ما محتوی دیتای ارسالی توسط کاربر در بندهء خودش هست و متدی که توسط مرورگر در درخواست مشخص میشه از نوع POST خواهد بود.

تگ فرمی با متد GET به این شکل نوشته میشه:
کد:
<form ... method="get">
و تگ فرمی که اطلاعات رو با متد POST ارسال میکنه به این شکل:
کد:
<form ... method="post">

بر اساس پروتکل HTTP، متد GET نباید برای درخواست هایی که هربار اجرای اونها موجب تغییری در سرور میشه مورد استفاده قرار بگیره. اونطور که بنده فهمیدم، کاربرد اصلی متد GET برای دریافت اطلاعات هست، نه ارسال اطلاعاتی که بخصوص هر بار باعث ایجاد تغییراتی در سمت سرور میشن. شاید از اسم این متد هم بشه به هدف واقعی اون که گرفتن اطلاعات موجود بر روی سرور هست، و نه ذخیره کردن یا تغییر دادن چیزی، پی برد.

بطور مثال این لینک رو درنظر بگیرید:

کد:
http://yoursite.com/add_credit.php?to=3546&amount=500

همونطور که باید قابل حدس باشه، این لینک باعث میشه که مقدار 500 تا اعتبار به کاربری با آیدی 3546 اضافه بشه. مسلما اجرای این درخواست موجب تغییر وضعیتی در سمت سرور میشه. یعنی مقدار اعتبار کاربر در دیتابیس به ازای هربار فراخوانی این لینک اضافه میشه. ضمنا این فقط فراخوانی بار اول نیست که تغییر ایجاد میکنه، بلکه هربار فراخوانی وضعیت سمت سرور رو تغییر میده و اثر جدیدی میذاره. تغییری که بر اثر دو درخواست پشت سرهم ایجاد میشه برابر با اثر یک درخواست نیست.

گرچه چنین کاربردهایی که مثال زدیم خیلی متداول هستن، اما در اصل این کاربردها برخلاف استانداردهای ذکر شده در پروتکل HTTP هستن.
خب این طبیعی هست چون خیلی افراد از این قضیه اطلاع ندارن و البته شاید یکی از دلایل دیگر این نقض استاندارد هم این باشه که کار کردن با متد GET بخصوص درموقع توسعه و تست، راحتتر و سریعتر از متد POST هست. فرمانها و متغییرها و مقدار اونها رو میشه در URL براحتی دید و دستکاری کرد و نوشتن کد درخواست های GET در برنامه معمولا راحتتر و سریعتر هست (نیازی به یک فرم نداریم و یک خط آدرس بسادگی این کار رو انجام میده).

روش صحیح برای چنین اعمالی استفاده از متد POST هست. یعنی باید یک فرم داشته باشید که سابمیت بشه. حالا مثلا با کلیک بر روی یک دکمه یا هر روش دیگری.

اگر دقت کنید رفتار مرورگرها هم منطبق با استاندارد پروتکل HTTP هست.
بطور مثال وقتی شما میخواید صفحه ای رو که با متد POST فراخوانی شده رفرش کنید، مرورگر به شما پیام هشداری نشون میده مبنی بر اینکه با فراخوانی مجدد اون صفحه، اطلاعات POST شده مجددا ارسال خواهند شد و از شما بابت این کار تایید میخواد، چون ارسال مجدد این اطلاعات که به معنای ارسال مجدد یک درخواست POST هست میتونه (البته لزوما اینطور نیست) موجب تغییر وضعیت مجدد در سمت سرور بشه و شاید هدف شما از سابمیت کردن مجدد اون اطلاعات واقعا ایجاد یک تغییر جدید نبوده باشه.

خب این بود خلاصهء ماجرا!

البته در این موضوع هنوز برای بنده ابهامات و سوالاتی وجود داره.
درمورد چیزهایی مثل http://yoursite.com/add_credit.php?to=3546&amount=500 تقریبا مطمئن هستم که متد GET استاندارد نیست و باید از متد POST استفاده بشه.
اما بطور مثال درمورد صحیح بودن یا نبودن استفاده از متد GET برای درخواست هایی که فقط در بار اول موجب ایجاد تغییری در سمت سرور میشن و در درخواست های بعدی بی اثر هستن مطمئن نیستم. بطور مثال آدرسی مثل http://yoursite.com/delete_post.php?post_id=68820 فرضا باعث حذف پست شماره 68820 میشه و اگر فرض کنیم برای همیشه فقط یک پست تحت این شماره در سایت ما وجود خواهد داشت و حتی درصورت حذف، هیچوقت پست دیگری با شمارهء مشابه در سایت ثبت نخواهد شد، پس این آدرس فقط یک بار موجب ایجاد تغییر میشه و هر تعداد فراخوانی های بعدی اون تفاوتی با یک فراخوانی بار اول ایجاد نخواهند کرد.

برطبق توضیحی که در بخش Idempotent methods and web applications مقالهء ویکیپدیا درمورد پروتکل HTTP آمده، بنظر میرسه استفاده از متد GET در چنین مواردی مطابق استاندارد باشه. اما در بخش Request methods همین مقاله آمده:
Requests using GET "SHOULD NOT have the significance of taking an action other than retrieval".
ترجمه: درخواستهایی که از متد GET استفاده میکنند نباید معنایی/اهمیتی غیر از انجام عمل بازیابی داشته باشند.

بنابراین بنده در تردید جدی هستم که استفاده از متد GET برای انجام عملی مثل حذف یک چیز، حتی اگر فقط یک نسخه از اون برای یک بار در سایت وجود خواهد داشت، مطابق استاندارد پروتکل HTTP باشه.

اما مجددا در بخش dempotent methods and web applications بیان شده که:

Methods PUT and DELETE are defined to be idempotent, meaning that multiple identical requests should have the same effect as a single request.

ترجمه: متدهای PUT و DELETE (م: به ترتیب باعث آپلود و حذف یک موجودیت بر روی سرور میشن) Idempotent تعریف شده اند، بدین معنا که درخواست های چندباره باید اثر یک درخواست تنها را داشته باشند.

در اینجا این سوال پیش میاد که آیا یک درخواست مثلا از نوع DELETE، درسته که بعد از باعث شدن مثلا حذف یک فایل خاص از روی سرور اگر دوباره اجرا بشه اثری نداره، اما فرضا اگر بعد از مدتی فایل دیگری مجددا با همون آدرس و نام روی سرور بوجود آمد (اصلا این امکان درمورد این متدها وجود داره یا نه؟)، آیا اگر درخواست DELETE قبلی تکرار بشه موجب یک عملیات حذف جدید روی یک فایل جدید (و احتمالا متفاوت و بی ارتباط با فایل اول) نمیشه؟ و اگر چنین چیزی میتونه رخ بده و برای متدهای Idempotent چنین چیزی مجاز هست، پس احتمالا ما میتونیم این استدلال رو به موارد مشابه درمورد متد GET هم اعمال کنیم.

برای اینکه بیشتر ذهن شما رو حیران کنم مثال مبهم تری رو مطرح میکنم:
http://yoursite.com/empty_basket.php
این درخواست GET مشخصا سبد خرید کاربر رو خالی میکنه.
آیا استفاده از متد GET برای چنین عمیاتی مجاز هست؟
بار اول که سبد خرید خالی میشه فراخوانی مجدد این آدرس اثری نداره، اما اگر سبد خرید دوباره حاوی اقلامی بشه، فراخوانی مجدد این آدرس موجب انجام عملیات جدیدی خواهد شد. حتی بازهم ابهام بیشتری از جهت دیگر در این موارد هست، چون این تغییرات معمولا در سشن و مکان ذخیره سازی موقت صورت میگیرن و تغییرات پایداری رو روی سرور باعث نمیشن. این تغییرات فقط در محدودهء فعالیت جاری کاربر نقش و کاربرد موقتی دارن.

فعلا میرم یه سری به RFC پروتکل HTTP هم بزنم و ببینم چیز بیشتری میفهمم یا نه. البته این پروتکل رو قبلا یک بار کامل خونده بودم و چند بار هم اینطور بخشهای اونو مطالعه کردم، ولی دقیق یادم نمیاد.

=====================

منبع: http://en.wikipedia.org/wiki/Http#Idempo...plications
  پاسخ
#2
باید اعتراف کنم از دقت نظر شما خوشم اومد و به جرأت عرض می کنم کم پیش اومده موضوعاتی اینچنینی در انجمنهای ما مطرح بشه سوالات شما ناشی از پرسشگری های ذهنی کاوشگر که اگر پاسخ این سوالات مطرح بشه ده ها سوال دیگه طرح میکنه برای همین از طرفی من به شخصه وقت پاسخگوئی به همه سوالات شما رو ندارم و از طرفی برخی از سوالات مطروحه نیاز به بررسی های شخصی خود من هم داره (یعنی پاسخ قطعی اونها رو نمی دونم و باید کمی جستجو کنم) به همین دلیل شما را ارجاع می دم به کتاب دوست عزیزم کریس شیفلت با عنوان HTTP Developer's Handbook کتاب توسط انتشارات Sams در سال 2003 به زینت چاپ آراسته شده و جز کتابهایی است که به بیشتر دوستان حرفه ای و فعال در این حوزه پیشنهاد می کنم علیرغم مشغله و دانش فنی که دارند حتما اون رو مطالعه بفرمایند
  پاسخ
تشکر شده توسط : vejmad admin parvane molana zoghal
#3
من الان بخشهای مرتبط RFC رو نگاهی کردم.
الان یخورده بیشتر مطمئن شدم که متد GET کلا نباید برای درخواست هایی که موجب ایجاد تغییر در سمت سرور میشن استفاده بشه. اصلا شاید نه فقط تغییر در سمت سرور، بلکه بطور کلی هر عملیاتی که ممکنه اثر مهمی روی کاربر یا دیگران داشته باشه!
چون ظاهرا نه تنها متد Idempotent و غیر Idempotent داریم، بلکه متدهایی هم داریم که Safe تعریف شدن و متد GET جزو اونهاست.
البته بازم 100% مطمئن نیستم.

ضمنا جواب این مسئله هرچی باشه بازهم مقداری تردید درمواردی مثل http://yoursite.com/empty_basket.php باقی میمونه بنظرم. چون نمیشه خالی کردن سبد خرید رو عملی خطرناک تلقی کرد و اثر پایدار مهمی روی سرور یا جای دیگه نمیذاره.

===================

منبع: http://tools.ietf.org/html/rfc2616#section-9.1

نقل قول:شما را ارجاع می دم به کتاب دوست عزیزم کریس شیفلت با عنوان HTTP Developer's Handbook کتاب توسط انتشارات Sams در سال 2003 به زینت چاپ آراسته شده و جز کتابهایی است که به بیشتر دوستان حرفه ای و فعال در این حوزه پیشنهاد می کنم علیرغم مشغله و دانش فنی که دارند حتما اون رو مطالعه بفرمایند
ممنون.
ولی اگر بشه جواب این یه مورد خاص رو سریعتر و راحتتر پیدا کنیم خیلی خوبه.
منکه دیگه از پا دراومدم و فعلا وقت و انرژی اضافه برای اولویت دادن به این کار ندارم.
ضمنا اصلا معلوم نیست این اطلاعات درش باشه یا نه.
راستی دانلودی مجانیش پیدا میشه؟ Big Grin

متاسفانه منابعش مثال نزدن. اگر نظیر چنین مواردی رو مثال میزدن احتمالا مشکلات و بی اطلاعی و مشکل در نتیجه گیری قطعی خیلی کمتر میبود.
  پاسخ
تشکر شده توسط : hosseintdk775 admin zoghal Bojbaj paull
#4
واقعا آفرین به vejmad
من هم یک سری حوابهایی رو دارم که شاید کامل نباشه
در مورد مثالهایی که زدید درسته نباید از GET استفاده بشه و باید از post استفاده بشه. اما بیشتر کاربران با همون post هم مشکل دارن.
یکی از مشکلات همون refresh دوباره هست. مرورگر پیغام میده اما. ۹۰ درصد کاربران اصلا به این موضوع اهمیت نمیدن. البته شاید بتونیم بگیم که به ما چه که اهمیت نمیدن . شاید درست باشه اما بحث یکی دو درصد نیست. به همین دلیل بهتره که کاربر رو بعد از انجام عملیات کلا ریداریکت کنیم. اینجوری با refreh و حتی دکمه بازگشت هم نمی تونه عملیات رو انجام بده. اما باز یک مشکل دیگه هم هست. درخواست به سرور میره و به دلیل سرعت پایین جوابی دریافت نمیشه. کاربر دوباره روی refresh میزنه. ( با این مشکل برخورد کردم ) حالا نه post به درد می خوره نه get . چه کار میشه کرد؟ قضیه CSRF یادته؟ راه حل چی بود؟ اضافه کردن یه فیلد hash . اگر بعد از درخواست شما دوباره اون فیلد هش رو تغییر بدید این مشکل و مشکل قبلی خود به خود با هم دیگه حل میشه.
  پاسخ
تشکر شده توسط : vejmad parvane hosseintdk775 zoghal Bojbaj paull
#5
بسم الله الرحمن الرحیم
سلام
در کنار این مطلب دوستمون این لینک رو هم مطالعه کنید:
HTTP is your Wrench
  پاسخ
تشکر شده توسط :
#6
از وقتی این مطلب vejmad و گفته های اساتید رو خوندم ، خیلی روی GET و POST حساس شدم. تمام تلاشم رو کردم روی برنامه هام حتماً همونطور که گفته شد عمل کنم ولی یه سوالی دارم. گاهاً اتفاق میافته که من در یک صفحه دارم یک فرم رو بصورت POST می فرستم ، بعد در جای دیگه از یک فرم جستجو که با GET ارسال میشه دارم یک مقدار رو فراخوانی می کنم که مثلاً برای عمل ویرایشش باید متصل بشه به اون فرم با POST ولی چون GET اومده ، نمیتونه POST بره برای همین چیزی در صفحه چاپ نمیشه. فعلاً برای اینکه کارم راه بیافته از متغیر REQUEST استفاده می کنم. بنظر شما ، امنیت REQUEST در چنین مواقعی نسبت به POST و GET چطوره و آیا راه دیگه ای هم هست؟
غایب
  پاسخ
تشکر شده توسط :


پرش به انجمن:


کاربران در حال بازدید این موضوع: 1 مهمان