|
حفاظت
از جريان
كنترلى برنامه
كاربردى وب نويسنده: Romain Guay چكيده: Struts،
برگرفته از Apache Jakarta Project، الگوى Synchronizer Token را به
منظور
پيشگيرى از
تكرار ارسال
فرم، پياده
سازى مىكند.
شما
مىتوانيد
اين وضعيت را
با بكارگيرى
الگوى مذكور
تشخيص دهيد و
هنگام بروز
اين حالت،
عملكرد
صحيحى را
انجام دهيد.
اما چه
عملكردى؟ در
اكثر موارد،
بهترين راه
كار ترميم (recover)
اولين نتيجه
ارسال است. اغلب
طراحان و
برنامه
نويسان
برنامه
كاربردى وب،
با وضعيتهايى
مواجه
مىشوند كه
بايد ارسال
فرم را در برابر
گسيختن
توالى عادى
جريان
كنترلى
محافظت
نمايند. اين
وضعيت در
زمانيكه
كاربر بيش از
يكبار بر روى
دگمه Submit پيش از
آنكه پاسخ
ارسال شود،
كليك مىكند
يا وقتى كه
كلاينت با
بازگشت به
صفحه bookmark
قبلى، به View
دسترسى پيدا
مىكند، روى
مىدهد. حفظ
توالى جريان
كنترلى (Control Flow) در
هنگامى كه
ارسال فرم
سبب پردازش
ارتباطات بر
روى سرور
مىشود، حائز
اهميت است. اين
مقاله راه
كار مشكل
مذكور را
ارائه مىنمايد:
استراتژيى
كه به صورت
كلاس
انتزاعى با
چهارچوب Strust
پياده سازى
مىشود. راه
كارهاى
كلاينت در
برابر راه
كارهاى سرور راه
كارهاى مختلفى
براى رفع
وضعيت ارسال
چندگانه فرم
وجود دارد.
بعضى از
سايتها به
كاربر هشدار
مىدهند كه پس
از ارسال
فرم، منتظر
دريافت پاسخ
باشد و از
ارسال مجدد
فرم بپرهيزد.
راه كارهاى
پيچيدهتر
شامل
اسكريپت
نويسى
كلاينت يا
برنامه نويسى
سرور هستند. در
استراتژى
كلاينت براى
اولين
ارسال، flag ست
مىشود و دگمه Submit
با توجه به
اين flag غيرفعال
خواهد شد. اين
استراتژى كم
وبيش به مرور
گر وابسته
است. در راه
كار مبتنى بر
سرور، الگوى Synchronizer Token (از
الگوهاى
اصلى J2EE) به كار
مىرود كه
كمترين
مشاركت را با client-side دارد. در
اين روش فرض
بر اين است كه token
در متغيير Session،
پيش از
بازگشت به
كلاينت، ست
شود. اين صفحه token
را درون فيلد
مخفى نگاه
مىدارد. در
هنگام ارسال،
ابتدا
پردازش
درخواست،
حضور token مجاز را
در پارامتر
درخواست،
بررسى مىكند.
بدين ترتيب
كه آن را با
يكى از tokenهاى ثبت شده
در Session مقايسه
مىكند. اگر token
مجاز بود،
پردازش روند
عادى خود را
طى مىكند. در
غيراينصورت token
به null ، Reset
مىشود تا از
ارسال مجدد
فرم پيشگيرى
شود. Token جديدى
در Session ذخيره
گردد. ذخيره token
جديد در زمان
مناسب و با
توجه به
جريان كنترلى
برنامه
كاربردى
مورد نظر
صورت مىگيرد.
به عبارتى
اجازه ارسال
دادهها در
زمان خاصى به
نمونهاى از view
داده مىشود.
اين الگوى Synchronizer Token، در
چهارچوب Struts
(Apache Jakarta project) مورد
استفاده
قرار مىگيرد.
اين چهارچوب
پياده سازى
رايج Model-View-Controller
مىباشد. عمليات
همگام راه
كار با توجه
به موارد فوق
تكميل شده
است. اما
موردى را
فراموش
نموديم.
چگونه
عمليات مورد
نظر را در
هنگام تشخيص token
غيرمجاز،
مشخص/ پياده
سازى نماييم.
در واقع در
حالتى كه
دوباره دگمه Submit
كليك شود،
درخواست دوم
سبب مىشود تا
اولين پاسخ
كه حاوى
نتيجه مورد
انتظار بوده
از بين برود. thread
كه اولين
درخواست را
اجرا مىكند،
باز هم اجرا
مىشود اما
نمىتواند
پاسخى را
براى مرورگر
داشته باشد.
لذا، شايد
كاربر تصور
كند كه
ارتباط به
طور كامل
صورت
نگرفته، در
حاليكه
ارتباط با
موفقيت كامل
شده است. استراتژى
مبتنى بر
چهارچوب Struts،
راه كار
كاملى فراهم
مىآورد كه از
ارسال مجدد
پيشگيرى
خواهد شد.
پياده سازى
پيشنهادى،
از كلاس
انتزاعى SynchroAction بهره
مىگيرد كه در
آن عمليات در
حالت همگام
قابل گسترش
هستند. اين
كلاس متد PerformSynchro()
انتزاعى را فراهم
مىآورد.
كنترل با
توجه به
وضعيت همگام
سازى به صورت
ذيل خواهد
بود: public final ActionForward perform(ActionMapping mapping, ActionForm
form,
HttpServletRequest request,
HttpServletResponse response) throws
IOException, ServletException { HttpSession
session = request.getSession(); ActionForward
forward = null; if (isTokenValid(request))
{ // Reset
token and session attributes reset(request); try { // Perform
the action and store the results forward =
performSynchro(mapping, form, request, response); session.setAttribute(FORM_KEY,
form); session.setAttribute(FORWARD_KEY,
forward);
ActionErrors errors = (ActionErrors)
request.getAttribute(Action.ERROR_KEY); if (errors
!= null && !errors.empty()) {
saveToken(request); } session.setAttribute(ERRORS_KEY,
errors); session.setAttribute(COMPLETE_KEY,
"true"); } catch (IOException e) { // Store
and rethrow the exception session.setAttribute(EXCEPTION_KEY,
e); session.setAttribute(COMPLETE_KEY,
"true"); throw e; } catch (ServletException
e) { // Store
and rethrow the exception session.setAttribute(EXCEPTION_KEY,
e); session.setAttribute(COMPLETE_KEY,
"true"); throw e; } } else { // If the
action is complete if ("true".equals(session.getAttribute(COMPLETE_KEY)))
{ // Obtain
the exception from the session
Exception e = (Exception) session.getAttribute(EXCEPTION_KEY); // If it
is not null, throw it if (e !=
null) { if (e instanceof IOException) {
throw (IOException) e; }
else if (e instanceof ServletException) {
throw (ServletException) e; } } // Obtain
the form from the session
ActionForm f = (ActionForm) session.getAttribute(FORM_KEY); // Set
it in the appropriate context if ("request".equals(mapping.getScope()))
{
request.setAttribute(mapping.getAttribute(), f); } else {
session.setAttribute(mapping.getAttribute(), f); } // Obtain
and save the errors from the session
saveErrors(request, (ActionErrors)
session.getAttribute(ERRORS_KEY)); // Obtain
the forward from the session forward =
(ActionForward) session.getAttribute(FORWARD_KEY); } else { // Perform
the appropriate action in case of token error forward =
performInvalidToken(mapping, form, request, response); } } return forward; } (چنانچه
سوس فوق در
مرورگر شما
بطور درست
نمايش داده
نمي شود، بر
روي اين لينك
كليك كنيد) همانگونه
كه در فوق
ملاحظه
نموديد، اين
عمليات در
صورتيكه token
مجاز باشد،
فقط يكبار
انجام مىشود.
اگر در هنگام
اجراى
عمليات
درخواستهاى
ديگر دريافت
گردد، به
نتيجه متد PerformInvalidToken() هدايت
مىشوند تا
عمليات كامل
گردد. به طور
پيش فرض اين
متد به سادگى ActionForward با نام “Synchro Error” باز
مىگرداند.
بدين ترتيب
به صفحه
اطلاع مىدهد
كه عمليات در
حال انجام
است و دگمهاى
را براى
ادامه
عمليات
فراهم
مىآورد. اين
دگمه همان
عمليات را
بدون فرم يا
پارامتر،
دوباره ارسال
مىكند. وقتى
عمليات كامل
شد، فرم،
استثنا و خطاها
در صورت
وجود، در Session
ذخيره و flag را
ست مىكند تا
مشخص شود كه
عمليات كامل
شده است. اولين
درخواست
فرم، استثنا
و خطاها
را پس از
تكميل
عمليات از Session
دريافت
مىكند و روند
ادامه
مىيابد. حفظ
سازگارى
كنترل جريان ارسال چند فرم ممكن است سبب بروز ناسازگارى در ارتباطات شود و بايد از اينكار ممانعت بعمل آورد. بدين منظور از الگوى Synchronizer Token استفاده مىشود. استراتژى پيشنهادى در اين مقاله به زيبايى اين الگو را براى ترميم پاسخ و حفظ جريان كنترل در برنامههاى كاربردى وب به كار برده است. منابع ·
Download this article's source including an example use of the
proposed strategy: ·
Learn more about Core J2EE Patterns, best practices, and design
strategies: ·
The Struts homepage: ·
For a client-only strategy to prevent duplicate form submission: ·
For more articles on design patterns, see the following JavaWorld
resources: o
The Design Patterns section of JavaWorld's
Topical Index: o
David Geary's Java Design Patterns column: |