العربية

أدوات المطور · URL التشفير وفك التشفير

escape() vs encodeURIComponent: كيف تطور ترميز JavaScript URL

· خلفية

جافا سكريبت ترميز URL تاريخ

ثلاثة أجيال من وظائف التشفير JavaScript URL
الرسم التوضيحي المتجه الأصلي ToolAcre

JavaScript لديه ثلاثة أجيال من وظائف التشفير URL، وما زال أقدمها كامنًا في كود الإنتاج. يشرح هذا المنشور الخطأ الذي يفعله الهروب () ولماذا قام ES3 بإضافة وظائف URI ولماذا يحتفظ بها! * '( ).

%u20AC في السجل القديم - بصمة الهروب التي لا لبس فيها () وفشل فك التشفير الذي يسببه

يحتوي الملف القديم JavaScript على استدعاء ترميز URL باستخدام وظيفة escape() المهملة. يتضمن الإخراج في ملف سجل أو رسالة خطأ التسلسل %u20AC - بصمة لا لبس فيها لوظيفة الهروب () المهملة التي لا يستخدمها أي شخص آخر. لا يتطابق هذا التسلسل مع أي ترميز قياسي URL، ولن يتعرف عليه جهاز فك التشفير المبني على قواعد RFC 3986 أو WHATWG. لا يمكن للبيانات أن تنتقل ذهابًا وإيابًا عبر الأدوات الحديثة. إنها علامة شائعة للتعليمات البرمجية تسبق ES3 ولم يتم تحديثها منذ التسعينيات.

تم تصميم الدالة escape() في عصر Netscape، قبل أن يكون لدى JavaScript معايير أو قواعد ترميز URL رسمية. يقوم بتشفير معظم الأحرف غير ASCII باستخدام تدوين %uXXXX، وهو رمز سداسي عشري مكون من أربعة أرقام لا يستخدمه أي شخص آخر ولا يوجد معيار محدد في أي مكان. كان هذا منطقيًا للاستخدامات لمرة واحدة داخل المتصفح، ولكنه أدى إلى انتهاك التوافق مع معايير URL وجعل من المستحيل فك تشفير البيانات في مكان آخر.

escape() وunescape(): تصميم عصر Netscape — الافتراضات اللاتينية 1 واختراع %uXXXX ولماذا لم يتطابق مطلقًا مع أي معيار

يفترض escape() وunescape() أن الإدخال هو Latin-1 (ISO 8859-1)، وهو ترميز الأحرف الذي سبق UTF-8 وUnicode. يقومون بتحويل كل حرف إلى رمز سداسي عشري، باستخدام %XX للأحرف اللاتينية عالية البت-1 و%uXXXX لكل شيء خارج اللاتينية-1. لا يمكن تمثيل حرف غير لاتيني 1 مثل الرموز التعبيرية على الإطلاق. الوظائف بسيطة وسريعة، ولكنها أيضًا غير مناسبة تمامًا لأي حالة استخدام حديثة.

تمت إضافة كلتا الدالتين إلى JavaScript قبل وجود المعايير. لقد تم إهمالها فورًا بعد أن قدم ES3 ترميز URL المناسب في 1999. وتظل في JavaScript للتوافق مع الإصدارات السابقة، حيث أن إزالتها ستؤدي إلى كسر التعليمات البرمجية القديمة. لكن أي كود جديد لا يجب أن يستخدمها أبدًا. إنهم بقايا تراث.

ES3 (1999) يضيف encodeURI وencodeURIComponent - UTF-8 ترميز النسبة المئوية محاذاة مع RFC 2396

قدم ES3 وظيفتين: encodeURI وencodeURIComponent. يقوم كلاهما بإجراء ترميز بنسبة UTF-8 بالنسبة المئوية: قم بتحويل الأحرف غير ASCII إلى UTF-8 بايت، ثم اكتب كل بايت كـ %HH. كلاهما يتوافق مع RFC 2396، والذي كان ساريًا في ذلك الوقت. RFC 3986 جاء لاحقًا ولم يغير سلوك التشفير. لا تزال هذه الوظائف هي المعيار اليوم ويجب استخدامها.

المقصود من encodeURI هو ترميز URI الكامل؛ الغرض من encodeURIComponent هو تشفير مكون داخل URI، مثل قيمة الاستعلام أو مقطع المسار. الفرق مهم للغاية ومن السهل إساءة فهمه. يحافظ encodeURI على الأحرف الهيكلية مثل: /؟ # @ = & و ;. يقوم encodeURIComponent بتشفير كل هذه العناصر، مما يجعلها آمنة للتضمين داخل URI أكبر.

لماذا ! * ' ( ) لا تزال غير مشفرة - تم تجميد أحرف RFC 2396 في اللغة بعد نقلها RFC 3986

تترك كلتا الدالتين هذه الأحرف غير مشفرة: الحروف والأرقام والواصلة (-) والشرطة السفلية (_) والنقطة (.) والتيلدا (~) وعلامات الترقيم الخمس! * '( ). جاءت العلامات من RFC 2396، والتي أدرجتها كأحرف "علامة" غير محجوزة. RFC 3986 ظهر في 2005 ونقل هؤلاء الخمسة إلى فئة مختلفة، ولكن JavaScript قام بالفعل بتجميد encodeURI وencodeURIComponent في 1999. سيؤدي تغيير الأحرف التي يتركونها بمفردها إلى كسر التعليمات البرمجية الموجودة، لذلك بقوا.

إن قرار الإبقاء على هذه العلامات الخمس غير مشفرة للتوافق مع الإصدارات السابقة يعني أن ترميز JavaScript لا يتطابق تمامًا مع RFC 3986 أو معيار WHATWG. إنه قريب بما فيه الكفاية للاستخدام العملي، وتغييره الآن مستحيل تماما. هذا درس في استقرار API: بمجرد تجميد السلوك، لا يمكنك تغييره حتى لو تطور المعيار.

مثال عملي: نفس السلسلة من خلال الهروب وencodeURI وencodeURIComponent - مقارنة ثلاثة مخرجات

خذ السلسلة "R&D (research) = Cafe's". قم بتشغيله من خلال escape() وencodeURI وencodeURIComponent. يُنتج الدالة escape() "R%26D%20(research)%20%3D%20caf%E9's"، حيث تخلط الأقواس غير المشفرة والفاصلة العليا مع علامة الضم المرمزة بنسبة مئوية وتساوي. ينتج encodeURI "R&D%20(research)%20=%20caf%C3%A9's"، مع ترك علامات الضم والمساواة بمفردها لأنها هيكلية. ينتج encodeURIComponent "R%26D%20%28research%29%20%3D%20caf%C3%A9%27s"، ويقوم بترميز كل شيء بما في ذلك الأقواس والفاصلة العليا.

الصق نفس السلسلة في برنامج التشفير ووحدة فك التشفير URL وقم بالتبديل بين encodeURI وencodeURIComponent لمعرفة الفرق. ثم افحص ما سينتجه الهروب () (يمكنك استدعاؤه في وحدة تحكم المتصفح، على الرغم من أنه سيحذرك). ترى على الفور أن الوظائف الثلاث تنتج ثلاث نتائج مختلفة تمامًا.

الترحيل بعيدًا عن الهروب () — تعيين الاستدعاءات القديمة إلى الوظيفة الحديثة الصحيحة ومعالجة بيانات %uXXXX المخزنة

يجب تحديث الكود القديم الذي يستخدم escape(). إذا تم استخدام escape() لترميز مكون URI، فاستبدله بـ encodeURIComponent. إذا تم استخدامه لتشفير URI كاملة، فاستخدم encodeURI. بالنسبة للبيانات المخزنة التي تحتوي على تسلسلات %uXXXX، تحتاج إلى وحدة فك ترميز مخصصة: قم بتحويل كل %uXXXX إلى نقطة رمز Unicode، ثم قم بتجميع نقاط الرمز في سلسلة. سوف يقوم unescape() المدمج في JavaScript بقراءة %uXXXX، ولكن النتيجة قد لا تكون صحيحة UTF-8.

بعد استبدال escape()، اختبر الكود باستخدام سلاسل تحتوي على أحرف غير ASCII وعلامات الترقيم والأحرف الخاصة. يجب أن يتوافق الناتج الآن مع ما تتوقعه الأدوات والمعايير الحديثة. إذا كان الكود الخاص بك يسبق ES3 بشكل ملحوظ، فقد يستخدم أيضًا أنماطًا قديمة أخرى؛ التدقيق الشامل يستحق كل هذا الجهد.

ما لا يغطيه هذا — واجهات برمجة التطبيقات URL وURLSearchParams، والتي يتم تناولها بشكل منفصل

توفر واجهات برمجة التطبيقات URL وURLSearchParams، التي تمت إضافتها لاحقًا، واجهات ذات مستوى أعلى لبناء URL وترميز المكونات. إنهم يتعاملون مع جميع حالات الهروب تلقائيًا ويطابقون معيار WHATWG URL تمامًا. إنها الطريقة المفضلة لإنشاء عناوين URL برمجيًا في JavaScript الحديثة.

يغطي هذا المنشور وظائف التشفير فقط، وليس واجهات برمجة التطبيقات ذات المستوى الأعلى. URL وبنية التحليل URLSearchParams، حدد قواعد المكونات وإجراء تسلسل للنتيجة، بينما يقوم encodeURIComponent بتحويل سلسلة واحدة مقدمة دون معرفة مكان وضعها. هذا التمييز هو الحد: قم بترحيل استدعاء escape() القديم وفقًا لما إذا كان يعالج قيمة أو عنوانًا، ثم فكر في استبدال التسلسل اليدوي المحيط بواجهات برمجة التطبيقات المنظمة كعامل إعادة بناء منفصل.

الوجبات الجاهزة: ثلاث وظائف، زوج واحد على قيد الحياة - كيف يُظهر برنامج التشفير ووحدة فك التشفير URL سلوك encodeURI الحديث وسلوك encodeURIComponent جنبًا إلى جنب

يجب أن يستخدم تطوير JavaScript الحديث encodeURI أو encodeURIComponent، ولا يهرب أبدًا (). تم توحيد الوظائف في 1999 ولم تتغير منذ ذلك الحين. يقومون بتشفير أحرف غير ASCII على هيئة UTF-8 بايت ويتعاملون مع الأحرف القياسية المحجوزة بشكل صحيح. تقوم أداة التشفير وفك التشفير URL بتنفيذ كلتا الوظيفتين وتتيح لك رؤية سلوكهما جنبًا إلى جنب، مما يجعل من السهل اختيار الوظيفة المناسبة للمكون الخاص بك.

إذا واجهت تسلسلات %u في السجلات القديمة أو البيانات المخزنة، فهي مخرجات escape() ويجب ترحيلها. يصبح الترحيل واضحًا بمجرد تحديد النمط. لا ينبغي للكود الحديث أن ينتجها أبدًا.