اذهب إلى المحتوى

كائنات URL في جافاسكربت


ابراهيم الخضور

يقدم الصنف URL المدمج واجهةً ملائمةً لإنشاء عناوين الموارد وروابط URL وتفسيرها، لا تحتاج الطلبات عبر الشبكة إلى هذا الكائن بالتحديد، فالقيم النصية التي يمكن أن تعبّر عن العناوين كافية، وبالتالي لن نحتاج إليه تقنيًا، لكننا سنجد أن استخدامه مفيد في مناسبات عدة.

إنشاء رابط URL

إليك الصيغة البرمجية التي تُنشئ كائن URL جديدًا:

new URL(url, [base])
  • url: عنوان URL الكامل، أو جزء منه عند إسناد قيمة إلى base.
  • base: أساس اختياري للعنوان، فإذا أسندت قيمة لهذا الوسيط وكانت قيمة الوسيط الآخر url هي مسار فقط، فسيُولّد الكائن URL منسوبًا إلى القاعدة base.

إليك مثالًا:

let url = new URL('https://javascript.info/profile/admin');

لاحظ أن كائني URL التاليين متطابقين تمامًا:

let url1 = new URL('https://javascript.info/profile/admin');
let url2 = new URL('/profile/admin', 'https://javascript.info');

alert(url1); // https://javascript.info/profile/admin
alert(url2); // https://javascript.info/profile/admin

يمكن بالطبع إنشاء كائن URL جديد مبني على مسار نسبي أساسه كائن URL موجود مسبقًا:

let url = new URL('https://javascript.info/profile/admin');
let newUrl = new URL('tester', url);

alert(newUrl); // https://javascript.info/profile/tester

نستطيع الوصول إلى مكوّنات الكائن URL مباشرةً، وبالتالي سيقدم طريقةً أنيقةً لتفسير العناوين:

let url = new URL('https://javascript.info/url');

alert(url.protocol); // https:
alert(url.host);     // javascript.info
alert(url.pathname); // /url

URL_components_01.png

إليك لائحةً بمكوّنات URL:

  • href: ويعيد العنوان كاملًا، تمامًا كما يفعل التابع ()url.toString.
  • protocol: جزء من العنوان ينتهي بالنقطتين ":".
  • search: سلسلة نصية من المعاملات يبدأ بإشارة الاستفهام "؟".
  • hash: ويبدأ بالعلامة "#".
  • كما يمكنك أن تجد الخاصيتين user وpassword عند استخدام استيثاق HTTP، مثل http://login:password@site.com، لكنه نادر الاستخدام.
اقتباس

يمكن تمرير كائنات URL مثل وسيط إلى طلب عبر الشبكة، بدلًا من تمرير قيمة نصية. يمكن استخدام هذا الكائن مع fetch أو XMLHttpRequest أو في أي مكان يوجد فيه عنوان URL على شكل قيمة نصية، إذ تُجري معظم الطلبات عملية تحويل إلى نص، وبالتالي سيتحول الكائن URL إلى نص يحمل عنوان URL كاملًا.

معامل البحث "?"

لنفترض أننا سننشئ عنوان url له معاملات بحث محددة، مثل https://google.com/search?query=JavaScript، كما يمكننا وضع المعاملات عند إنشاء كائن URL:

new URL('https://google.com/search?query=JavaScript')

ويجب ترميز المعاملات إذا احتوت على فراغات أو أحرف ليست لاتينيةً وما شابه (ستجد المزيد عن ذلك في الفقرات التالية)، لذلك توجد خاصية تتولى ذلك هي url.searchParams، وهي كائن من النوع URLSearchParams، وتؤمن مجموعةً من التوابع التي تتعامل مع معاملات البحث:

  • (append(name, value: يضيف المعامل المحدد بالاسم name.
  • (delete(name: يحذف المعامل المحدد بالاسم name.
  • (get(name: يحضر المعامل المحدد بالاسم name.
  • (getAll(name: يحضر كل المعاملات التي لها نفس الاسم name، وهو أمر ممكن، مثل ?user=John&user=Pete.
  • (has(name: التحقق من وجود معامل بالاسم name.
  • (set(name, value: لضبط معامل أو تغييره.
  • ()sort: فرز المعاملات بالاسم، وتُستخدّم نادرًا، وهي قابلة للمرور عليها Iterable بصورة مشابهة للترابط Map.
let url = new URL('https://google.com/search');

url.searchParams.set('q', 'test me!'); //! يضيف معاملًا ضمنه فراغ وإشارة  

alert(url); // https://google.com/search?q=test+me%21

url.searchParams.set('tbs', 'qdr:y'); // ":" يضيف معاملًا يحوي العلامة

// تُرمز المعاملات تلقائيًا
alert(url); // https://google.com/search?q=test+me%21&tbs=qdr%3Ay

//(المرور على المعاملات (فك ترميز
for(let [name, value] of url.searchParams) {
  alert(`${name}=${value}`); // q=test me!, then tbs=qdr:y
}

الترميز Encoding

يحدد المعيار RFC3986 المحارف المسموحة في العناوين، والمحارف التي لا يُسمح باستخدامها. وينبغي ترميز المحارف التي لا يسمح بها، مثل الأحرف غير اللاتينية والفراغات، باستبدالها بمقابلاتها في ترميز UTF-8 مسبوقًا بالمحرف "%"، كأن نكتب 20%. ويمكن ترميز الفراغ بالمحرف "+" لأسباب تاريخية -وهذه حالة استثنائية-، لكن الجيد بالأمر هو أنّ الكائن URL ينجز كل ذلك تلقائيًا، وكل ما علينا فعله هو تزويده بالمعاملات دون ترميز، وسيحول العنوان إلى نص:

// using some cyrillic characters for this example

let url = new URL('https://ru.wikipedia.org/wiki/Тест');

url.searchParams.set('key', 'ъ');
alert(url); //https://ru.wikipedia.org/wiki/%D0%A2%D0%B5%D1%81%D1%82?key=%D1%8A

لاحظ أن القيمتين Тест في مسار العنوان وъ في المعامل قد رُمِّزا، سيغدو العنوان أطول لأن كل محرف سيُمثّل ببايتين في UTF-8، وبالتالي ستكون هناك كتلتان من الشكل ..% لكل محرف.

ترميز القيم النصية

استخدم المبرمجون -في السابق وقبل ظهور الكائن URL- القيم النصية لتمثيل العناوين، لكن استخدام الكائن URL حاليًا أكثر ملاءمةً، ومع ذلك لا يزال استخدام القيم النصية شائعًا، فهو يجعل العنوان أقصر في الكثير من الأحيان، ولا بدّ عند استخدام القيم النصية من ترميز أو فك ترميز المحارف الخاصة يدويًا، باستخدام دوال مدمجة هي:

  • encodeURI: يُرمِّز العنوان بالكامل.
  • decodeURI: يفك ترميز النص المرمَّز.
  • encodeURIComponent: يرمّز مكوّنًا من مكونات العنوان، مثل معاملات البحث أو المسار.
  • decodeURIComponent: يفك ترميز الجزء المُرمَز.

لكن السؤال الطبيعي سيكون: "ما هو الفرق بين encodeURIComponent وencodeURI؟ ومتى سنستخدم كلًا منهما؟"

من السهل استيعاب الفكرة عند النظر إلى الصورة السابقة التي تفصل العنوان التالي إلى مكوناته:

https://site.com:8080/path/page?p1=v1&p2=v2#hash

إذ يُسمح باستخدام المحارف التالية : و? و= و& و# في عنوان URL، ومن جهة أخرى إذا نظرنا إلى أي مكوّن من مكوّنات العنوان بمفرده، مثل: المعاملات، فلا بدّ من ترميز هذه المحارف حتى لا تخِلّ بتنسيق العنوان.

وهنا سنرى استخدام الدالتين السابقتين:

  • encodeURI: تُرمز المحارف المرفوضة كليًا في العناوين فقط.
  • encodeURIComponent: ترمز نفس المحارف التي ترمزها الدالة السابقة بالإضافة إلى المحارف التالية: # و$ و& و+ و, و/ و: و; و= و? و@.

لذلك يمكن استخدام الدالة encodeURI لترميز العنوان كاملًا:

// using cyrillic characters in url path
let url = encodeURI('http://site.com/привет');

alert(url); // http://site.com/%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82

بينما ستستخدم الدالة encodeURIComponent في ترميز معاملات العنوان:

let music = encodeURIComponent('Rock&Roll');

let url = `https://google.com/search?q=${music}`;
alert(url); // https://google.com/search?q=Rock%26Roll

لاحظ الفرق عند استخدام encodeURI:

let music = encodeURI('Rock&Roll');

let url = `https://google.com/search?q=${music}`;
alert(url); // https://google.com/search?q=Rock&Roll

حيث لا تُرمّز الدالة encodeURI المحرف & لأنه محرف مقبول في عنوان URL الكامل، لكن لا بدّ من ترميزه عندما يكون ضمن معامل البحث، وإلا ستكون نتيجة q=Rock&Roll هي q=Rock، بالإضافة إلى معامل غامض يمثله Roll، وهي ليست كما قصدنا.

لذا لا بدّ من استخدام encodeURIComponent فقط عند تشفير كل معامل من معاملات البحث، لكي نضعه بشكله الصحيح في نص العنوان، وتبقى طريقة ترميز الاسم والعنوان معًا هي الأكثر أمانًا؛ إلا عندما نثق تمامًا بعدم احتواء أي منهما على محارف ممنوعة الاستخدام.

اقتباس

اختلافات التشفير بالنسبة إلى العناوين URL بُني الصنفان URL وURLSearchParams على التوصيفات الأخيرة للعناوين URI ضمن المعيار RFC3986، بينما بُنيت الدوال *encode على النسخة RFC2396 المنتهية المفعول. ستجد بعض الاختلافات بينهما مثل عناوين IPv6 التي ستُرمَّز بشكل مختلف:

// valid url with IPv6 address
let url = 'http://[2607:f8b0:4005:802::1007]/';

alert(encodeURI(url)); // http://%5B2607:f8b0:4005:802::1007%5D/
alert(new URL(url)); // http://[2607:f8b0:4005:802::1007]/
اقتباس

وكما نرى ستستبدل الدالة encodeURI محتوى الأقواس المربعة [...] غير الصحيحة كونها عنوان IPv6، فلم تكن هذه العناوين موجودةً في زمن المعيار (أغسطس "آب" 1998)، وهذه الحالات نادرة، لذلك ستعمل الدوال *encode جيدًا في معظم الأوقات.

ترجمة -وبتصرف- للفصل URL Objects من سلسلة The Modern JavaScript Tutorial.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...