ایجاد ارتباط در وب از طریق جاوا اسکریپت بین دامینهای متفاوت
به علت یک سری مسایل امنیتی و امکان استفاده های نادرست و غیرقانونی، مرورگرهای اینترنتی از طریق جاوا اسکریپت و به اصطلاح به صورت کلاینت ساید، مجاز به خواندن فرمت XML از سرور های دیگر نیستند و فقط میتوانند فایلهای XML موجود در همان آدرس سایتی را بخوانند که خودشان در آن دامین قرار دارند.
مثلا اگر در صفحه mytoolbox.ir/blog/FeedReader.html با استفاده از جاوا اسکریپت و ایجکس، درخواستی برای msn.com/test/test.xml بفرستیم، پیغام خطا برای مرورگر ما برگشت خواهد خورد با این عنوان که اجازه دسترسی به text.xml را در دامین msn.com نداریم و از FeedReader.html فقط میتوان به فایلهای XML موجود در آدرس mytoolbox.ir بدون پیغام خطا، درخواست داد.
در شکل زیر، همونطور که مشخص شده، یک فایل در آدرس localhost اجرا شده و درخواستی رو برای mytoolbox.ir فرستاده؛ این ارتباط موفقیت آمیز بوده (۲۰۰ OK) اما هیچ اطلاعاتی به localhost فرستاده نمیشود و در واقع یک فایل xml خالی فرستاده شده که کلاینت هم در خوندن اون دچار مشکل شده و پیغام خطا میده که چیزی در فایل درخواستی نیست.
همونطور که میدونید، RSS Feed هم به فرمت XML هست. بنابراین اگر بخواهیم فید وبسایت و یا وبلاگ دیگری را در سایت خودمون به کتر ببریم، با توجه به محدودیت فوق، این کار امکان پذیر نیست. قبلتر در جعبه ابزار نحوه خواندن فایلهای XML با جیکوئری را دیدید (تجزیه و تحلیل ایکس اِم اِل در جیکوئری). همونطور که اونجا هم اشاره شد، این روش برای وقتی هست که فایل XML روی سرور خود شما قرار گرفته باشد.
بر خلاف حالت کلاینت ساید، ارسال درخواست به سرورهای دیگر از طریق برنامه نویسی سمت سرور مثل ASP.Net و PHP، هیچ مشکلی ندارد و در صورت اجازه دسترسی به منابع سایتی مکه به آن درخواست میدهیم، پاسخ مناسب به سرور ما خواهد رسید. بنابریان به صورت سرورساید به سادگی و بدون مشکل میشود RSS سایتهای دیگر رو خواند و استفاده کرد.
اهمیت استفاده از جاوا اسکریپت و AJAX (بخوانیم ای جکس!) در طراحی های مدرن و به اصطلاح Web2.0 برخی مواقع شما رو مجبور میکنه که از تکنیکی برای خواندن فید و XML در کلاینت استفاده کنید. برای این کار، روشی به اسم JSONP ابداع شده است.
JSONP چیست؟
با توجه به مطالب بالا فهمیدیم که domain1 نمیتواند با domain2 انتقال اطلاعات در جاوا اسکریپت داشته باشد. اما آیا به این فکر نیوفتادید که پس CDN ها چطور کار میکنند؟ (در مورد CDN بیشتر بدانید.) در محدودیت ارتباط مرورگرها یک استثنا وجود داره و اون هم تگ اسکریپت <script> هست. تگ اسکریپت میتواند توسط src به یک فایل در دامین دیگری اشاره کند و آن فایل را بخواند.
بنابراین از همین روش میتوان محدودیت موجود را دور زد. سناریوی زیر را بخاونید تا کامل متوجه موضوع شوید؛ در این متن، mytoolbox.ir میخواهد با جاوا اسکریپت، RSS Feed سایت msn.com را بخواند:
اول: سایت msn.com یک آدرس رو معرفی میکند مثلا msn.com/feed/load.aspx و آن را در اختیار اشخاصی قرار میدهد که قصد دارند با جاوااسکریپت به فید دسترسی داشته باشند. پاسخ این فایل، همان مقادیر فید به صورت متنی خواهد بود.
دوم: سایت mytoolbox.ir آدرس فوق را در یک تگ اسکریپت به کار میبرد به این صورت:
<script src=http://msn.com/feed/load.aspx" type="text/javascript">
</script>
طرح مشکل: در حال حاضر، با اجرای صفحه حاوی اسکریپت، فید از سایت msn.com دانلود میشود اما چگونه باید به آن دسترسی داشته باشیم؟ در جاوا اسکریپت برای گرفتن مقادیر لود شده از یک فایل دیگر، باید از AJAX استفاده کنیم. اما دیدیم که در این مورد با AJAX اجازه نداریم این کار را بکنیم، پس با تکنیک کنونی باید چه کرد؟
راه حل: برای رفع این مشکل، msn.com اطلاعات خودش را به صورت یک تابع جاوااسکریپت برمیگرداند. یعنی در این مثال، اگر load.aspx را در مرورگر اینترتی ببینیم، به صورت زیر هست: (دقت کنید این مثال به صورت شماتیک قصد دارد موضوع رو بیان کند، بنابراین فرمت اطلاعات برگشتی خارج از بحث میباشد و فقط به صورت شماتیک data مینویسیم.)
ReadData("data data data …")
در واقع پاسخ، یک تابع با یک مقدار ورودی هست. بنابراین با تعریف این تابع، میتوانیم بعد از لود شدن این مقدار در تگ اسکریپت، به جاوا اسکریپت بفهمانیم که حالا با این تابع چی کار کند. بنابراین مشکل حل میشود!
سوم: تعریف تابع بازگشتی از msn.com در صفحه مورد نظر در mytoolbox.ir :
<script src=http://msn.com/feed/load.aspx" type="text/javascript">
</script>
<script type="text/javascript">
function ReadData(f) {
// do anything with f, for example:
// alert(f)
}
</script>
حالا وقتی اطالاعات از سرور msn.com لود شد، در واقع تابع ReadData صدا زده میشود که در آن گفتهایم مثلا این فید ارسالی را با فلان فرمت در فلان جای صفحه بنویسد. بدین ترتیب مشکل خواندن از دامین های دیگر، به این صورت حل میشود. به این مدل JSONP گفته میشود.
چرا به اسمِ JSONP ؟
در انتقال اطلاعات بین منابع مختلف، یکی از فرمتهای رایج XML هست، اما فرمت و ساختارهای دیگری هم وجود دارد. یکی از این فرمت ها که بسیار هم طرفداران پیدا کرده و روز به روز رواج بیشتری پبدا میکنه، فرمت JSON هست. این فرمت بیشتر در انتقال اطلاعات بین یک زبان سمت سرور مثل ASP.Net و برنامه نویسی سمت کلاینت یعنی جاوا اسکریپت استفاده میشود. شاید دلیلش این باشه که خوندن JSON (تلفظ: جِی سان) در جاوا اسکریپت خیلی ساده تز خوندن XML هست و نکته بعدی اینکه حجم فایلهای JSON در اکثر موارد مخصوصا زمانی که اطلاعات در حال انتقال حجم زیادی داشته باشند، نسبت به فرمت XML، کم حجم تر هست. (در مورد JSON بیشتر بدانید)
نمونه کد JSON بازگشتی از تکنیک JSONP به صورت زیر میباشد. دقت کنید که کد اصلی JSON از خط دوم شروع میشود و myfunc نام تابع جاوا اسکریپت هست.
myfunc(
{
"wesbite":"http://mytoolbox.ir",
"language":"Persian",
"post": {
"title":"Cross Domain Javascript",
"date":"25 Feb 2010"
}
}
);
تکنیک ذکر شده برای ایجاد ارتباط بین دامین های مختلف در سمت کلاینت، اولین بار که مطرح شد در مورد انتقال اطلاعات در فرمت JSON بود که توسط سرویس های یاهو استفاده شد. برای همین اسم این روش رو هم JSON with Padding و به اختصار JSONP نامیده شد. و البته این تکنیک با هر فرمتی میتونه اعمال شه چرا که در روش پیاده سازی این تکنیک، هیچ محدودیتی برای اطلاعات منتقل شده وجود ندارد، چه XML باشد چه JSON چه یک خط متن!
به دلیل استفاده سرویسهای بزرگ در اینترنت از فرمت JSON در انتقال اطلاعات به وسیله API های خودشون، تقریبا این فرمت در حال همه گیر شدن هست و یه جورایی داره استاندارد میشه و البته شخصا عقیده ندارم که JSON بتونه جای XML رو بگیره. حداقل اینکه مایکروسافت همچنان از فرمت XML در سرویسهای دات نت مثل WCF و XAML استفاده میکنه.
کتابخونه jQuery برای سهولت کار، از JSONP پشتیبانی میکند و شما نیازی نیست به صورت دستی اقدام به پیاده سازی تکنیک ذکر شده در این مطلب، کنید. در مورد نحوه استفاده از JSONP در jQuery در مطالب آینده جعبه ابزار خواهم نوشت.
مطلب آخر این که توجه کنید، برای استفاده از تکنیک JSONP، سروری که شما به آن درخواست میفرستید، باید از این تکنیک پشتیبانی کنه وگرنه سروری که به اون درخواست دادهایم اگر منظور ما رو از درخواست JSONP متوجه نشود، پاسخ مناسب رو به ما نخواهد داد. از کجا بفهمیم از JSONP پشتیبانی میکند؟ در ۹۹% موارد میشه گفت اگر سرویسی پاسخ خود به درخواست رسیده رو به فرمت JSON بدهد، از JSONP پشتیبانی میکند.
*این مطالب از خودم میباشد! اگر در اون مورد اشتباهی میبینید، ممنون میشم که اعلام کنید و استفاده از این مطلب آزاد هست و اگر دوست دارید با انصاف باشید، منبع رو هم ذکر کنید.
