ترميز وفك ترميز الروابط

ثلاثة أنماط للترميز بالنسبة المئوية جنبًا إلى جنب، لترى أيّها تحتاج.

ثلاث قواعد، واختيار الخطأ منها هو العلّة

يستبدل الترميز المئوي المحرف بعلامة % يتبعها قيمة بايته بالنظام الست عشري. بسيط بما يكفي. لكن ما يسبب المتاعب أن ثمة ثلاثة آراء مختلفة في أي المحارف يجب استبدالها، وهي تختلف بالضبط عند المحارف التي تهمّ.

القاعدةتهرّب / ? & = #المسافة تصيرتُستعمل لـ
encodeURIComponentنعم%20قيمة ذاهبة إلى داخل رابط
encodeURIلا%20ترتيب رابط كامل
ترميز النماذجنعم+ما يرسله نموذج HTML فعلاً

ولهذا السبب بالضبط تعرض الأداة الثلاث دفعةً واحدة. فقراءتها جنباً إلى جنب أسرع من الحكم النظري على أيّها كنت تقصد.

الخطأ الذي يمنعه هذا

افترض أن قيمة بحث هي coffee & cake. فترميزها بوصفها مكوّناً يجعلها coffee%20%26%20cake، ويصير الرابط:

/search?q=coffee%20%26%20cake

معامل واحد، والقيمة سليمة. أما بترميز encodeURI فتنجو علامة العطف كما هي:

/search?q=coffee%20&%20cake

الآن يرى الخادم معاملين — q قيمته «coffee » وهناك ثانٍ فارغ اسمه « cake». ولا خطأ يظهر. فالبحث يعيد نتائج خاطئة في صمت، وهذا من نوع العلل التي تنجو من المراجعة لأن الرابط يبدو سليماً.

علامة + التي ليست جمعاً

المصدر الموثوق الآخر للالتباس. ففي بيانات النماذج المرمَّزة تعني + مسافةً، ويجب كتابة علامة الجمع الحقيقية %2B. لذا فإن فكّ ترميز C%2B%2B بقاعدة النموذج يعطي C++، أما فكّ ترميز C++ فيعطي C — ومسافتين، وقد ضاع اسم اللغة.

وهذا يعضّ أشدّ ما يعضّ في أرقام الهواتف. فـ +44 20 7946 0958 إذا أُرسل عبر نموذج وفُكّ ترميزه بالقاعدة الخطأ صار 44 20 7946 0958، فاقداً بادئة رمز الدولة، ولا جهة تبلّغ عن خطأ.

ماذا تفعل بدل الترميز اليدوي

في جافاسكربت، ابنِ سلاسل الاستعلام بـ URLSearchParams لا بالدمج النصي. فهي تطبّق القاعدة الصحيحة على كل قيمة وتتعامل مع المفاتيح المكررة:

const url = new URL('https://example.com/search');
url.searchParams.set('q', 'coffee & cake');
url.searchParams.set('page', '2');
// https://example.com/search?q=coffee+%26+cake&page=2

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

قراءة رابط مرمَّز

ثمة تسلسلات قليلة تستحق أن تعرفها بمجرد النظر، لأنها تتكرر في السجلات باستمرار:

التسلسلالمحرفلماذا يهم
%20مسافةالأكثر شيوعاً بفارق كبير
%2F/شرطة مائلة مرمَّزة داخل المسار كثيراً ما تكون محاولة اجتياز مجلدات
%3A:شائع في الروابط المرمَّزة داخل معاملات إعادة التوجيه
%25%الترميز المزدوج يظهر بصيغة %2520
%00محرف فارغلا يكاد يكون مشروعاً أبداً

و%2520 بخاصة تستحق المعرفة: فهي %20 رُمّزت مرة ثانية. وهي تعني عادةً أن قيمةً مرّت عبر طبقتين رمّزتها كلٌّ منهما، وهي توقيع سلسلة إعادة توجيه أو وكيل يفعل ما لا ينبغي.

ذات صلة

لترميز البايتات لا لتهريب النصوص، فإن Base64 هو المهمة المختلفة. وإن تبيّن أن القيمة المفكوكة ملف JSON، فسيقرؤها المنسّق، وإن كانت رمزاً مميزاً فسيتولاها فاكّ ترميز JWT.

أسئلة حول الترميز

ما الفرق بين encodeURI و encodeURIComponent؟

تهرّب encodeURIComponent المحارف ذات المعنى البنيوي في الرابط — مثل ‎/ و? و& و= و# و: وغيرها — لأنها تفترض أن ما ترمّزه قيمة ستوضع داخل رابط. أما encodeURI فتتركها كما هي، لأنها تفترض أنك سلّمتها رابطاً كاملاً يحتاج ترتيباً فحسب. وترميز معامل استعلام بـ encodeURI هو الخطأ الشائع: إذ تنجو علامة & داخل القيمة فتشطر معاملك إلى اثنين في صمت.

لماذا تكون المسافة أحياناً ‎%20 وأحياناً +؟

كلاهما صحيح في سياقه. فـ ‎%20 هو الترميز المئوي العام للمسافة ويعمل في أي موضع من الرابط. أما اصطلاح + فمصدره application/x-www-form-urlencoded، وهي الصيغة التي تُرسَل بها نماذج HTML، وفيها يعني + مسافةً ويجب كتابة علامة الجمع الحقيقية ‎%2B. فالمسافة في المسار ‎%20، والمسافة في بيانات نموذج مُرسَل هي +. وفكّ ترميز بيانات النموذج بالقاعدة الخطأ يحوّل كل علامة جمع في نص المستخدم إلى مسافة.

ظهر لي خطأ «URI malformed». ما سببه؟

علامة نسبة مئوية لا يتبعها رقمان ست عشريان. وغالباً يكون سببها علامة ‎% حرفية في نص لم يُرمَّز قط — فرمز خصم مثل «‎50% off» كافٍ لذلك، لأن ‎%20 يُقرأ تسلسلَ هروب بينما ‎%off غير صالح. والعلامة الحرفية يجب أن تُكتب ‎%25. والسبب الآخر هو فكّ الترميز مرتين: فتشغيل فكّ الترميز مرتين على ما رُمّز مرة واحدة يصطدم في النهاية بعلامة ‎% كان يُفترض أن تبقى.

هل أرمّز الرابط كله أم القيم فقط؟

القيم فقط، في كل الأحوال تقريباً. ابنِ الرابط بنيوياً ورمّز كل معامل عند إدراجه — وفي جافاسكربت تتولى URLSearchParams ذلك عنك وهي أوثق من الترميز اليدوي. أما ترميز رابط كامل فلا معنى له إلا حين يُسلَّم إليك رابط مشوّه أصلاً وأنت ترقّعه.

هل يجعل ترميزُ الرابط الرابطَ آمناً؟

لا. الترميز المئوي شأن نحوي لا أمني — فهو يضمن أن تنجو القيمة عند وضعها في رابط دون أن تغيّر بنية الرابط. ولا شأن له بالوجهة التي يشير إليها الرابط، وليس دفاعاً ضد الحقن: فالقيمة المرمّزة ترميزاً صحيحاً للرابط تظل خطرة إن أُدرجت لاحقاً في HTML أو SQL دون التهريب الملائم لكل منهما.

آخر مراجعة . وجدت شيئاً لم يعد محدَّثاً؟ أخبِرنا.