ไทย

เครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ · URL ตัวเข้ารหัสและตัวถอดรหัส

บวกกับ %20: ประวัติการสมัคร/x-www-form-urlencoded

· พื้นหลัง

การเข้ารหัส URL แบบฟอร์ม html http-มาตรฐาน

การส่งแบบฟอร์มแสดงพื้นที่การเข้ารหัสเครื่องหมายบวกในสตริงการสืบค้นเทียบกับเปอร์เซ็นต์ยี่สิบในไวยากรณ์ URI
ภาพประกอบเวกเตอร์ต้นฉบับ ToolAcre

แบบฟอร์มเข้ารหัสช่องว่างเป็น + ในขณะที่มาตรฐาน URI ระบุว่า %20 และเหตุผลก็คือเหตุผลในอดีต โพสต์นี้ติดตามแบบแผนตั้งแต่แบบฟอร์ม HTML รุ่นแรกๆ จนถึงคำจำกัดความ WHATWG ในปัจจุบัน และอธิบายว่าทำไมจึงไม่หายไป

Plus กับ %20—เหตุใดแบบฟอร์มและ URI จึงเข้ารหัสช่องว่างต่างกัน

HTML แบบฟอร์มที่ส่งเป็น GET เข้ารหัสช่องว่างเป็นเครื่องหมายบวกในสตริงแบบสอบถาม ช่องว่างเดียวกันจะกลายเป็น %20 ใน URL ที่ตามหลัง RFC 3986 ทั้งสองถูกต้องเนื่องจากเป็นไปตามมาตรฐานที่แตกต่างกัน ฟิลด์แบบฟอร์มที่มีช่องว่างจะกลายเป็น name=value+with+spaces ในการเข้ารหัสแบบฟอร์ม แต่เป็น %20 ใน RFC 3986 ความแตกต่างบวกเปอร์เซ็นต์ยี่สิบเป็นเครื่องหมายมาตรฐานที่ใช้กับข้อมูลของคุณ

การเข้ารหัสแบบฟอร์มใช้เครื่องหมายบวกสำหรับการเว้นวรรคเป็นแบบแผนในอดีตจาก RFC 1866 (1995), HTML 2.0 คำจำกัดความการส่งแบบฟอร์มดั้งเดิม GET ขอช่องว่างที่เข้ารหัสเป็นเครื่องหมายบวก โดยสงวนเครื่องหมายบวกไว้สำหรับตัวอักษร + เข้ารหัสเป็น %2B กฎนี้ใช้กับ application/x-www-form-urlencoded, เท่านั้น ไม่ใช่ไวยากรณ์ URI ทั่วไป เฟรมเวิร์กเซิร์ฟเวอร์หลายพันล้านรายการขึ้นอยู่กับแบบแผนนี้ การทดสอบทั้งสองแสดงความแตกต่างที่ชัดเจน: โหมดฟอร์มจะสร้างเครื่องหมายบวก; โหมด URI สร้าง %20 URL ตัวเข้ารหัสและตัวถอดรหัสเสนอทั้งสองโหมดเพื่อเปรียบเทียบโดยตรง

แบบฟอร์ม HTML ล่วงหน้าและการส่ง GET — วิธีกำหนดการเข้ารหัสแบบฟอร์ม และเหตุใดจึงเลือก +

RFC 1866 (1995) กำหนดการส่งแบบฟอร์ม โดยที่ช่องว่างกลายเป็นเครื่องหมายบวก และเครื่องหมายบวกกลายเป็น %2B สิ่งนี้ใช้กับ application/x-www-form-urlencoded. RFC 3986 ที่ระบุ %20 สำหรับไวยากรณ์ URI ทั่วไปเท่านั้น สองมาตรฐานอยู่ร่วมกันอย่างจงใจ

RFC 2396 ตัวละครที่มีความชัดเจนกำหนดไว้อย่างเข้มงวดมากกว่ามาตรฐานก่อนหน้านี้ มันทำให้อักขระที่สงวนไว้อย่างเป็นทางการซึ่งให้บริการโครงสร้าง URI เทียบกับข้อมูลที่ไม่สงวนไว้เป็นตัวอักษร เนื้อหามาตรฐานจะจัดรูปแบบพฤติกรรมของเบราว์เซอร์และพร็อกซีเมื่อมีการพัฒนา RFC 3986 มาทีหลังโดยไม่เปลี่ยนพฤติกรรมการเข้ารหัส เพียงชี้แจงข้อความให้ชัดเจน เบราว์เซอร์ปัจจุบันทั้งหมดมีการเข้ารหัส UTF-8 ให้เป็นมาตรฐาน แบบฟอร์ม HTML ผ่านปุ่มส่ง ส่งรูปแบบแอปพลิเคชัน/x-www-form-urlencoded พร้อมเครื่องหมายบวกสำหรับการเว้นวรรค โครงสร้าง URI แบบแมนนวลใช้ %20 การทำความเข้าใจทั้งสองมาตรฐานจะป้องกันไม่ให้เกิดความประหลาดใจในการบูรณาการ

RFC 1866 และใหม่กว่า HTML ข้อกำหนด - ตำแหน่งที่เขียนกฎและวิธีที่แตกต่างจากไวยากรณ์ URI

WHATWG URL มาตรฐานระบุ URLSearchParams.toString() สร้าง application/x-www-form-urlencoded เอาต์พุตพร้อมเครื่องหมายบวกสำหรับการเว้นวรรค URL ตัวสร้างเปอร์เซ็นต์เข้ารหัสตาม RFC 3986 เบราว์เซอร์นำทางไปยัง URL ด้วยช่องว่างเข้ารหัส %20; แบบฟอร์มที่ส่งเป็น GET เข้ารหัสบวก เครื่องมือพื้นฐานที่แตกต่างกันเหล่านี้มีจุดประสงค์ที่แตกต่างกัน encodeURIComponent ด้วยตนเองให้ %20 สำหรับการเว้นวรรค—RFC 3986 สไตล์ แบบฟอร์มที่ส่งไปยัง URL เดียวกันส่งบวก เซิร์ฟเวอร์แยกวิเคราะห์การส่งแบบฟอร์มคาดหวังบวก; การรับ %20 ทำให้เกิดความล้มเหลวของพารามิเตอร์แบบเงียบ

การทดสอบทั้งสองอย่างเผยให้เห็นสมมติฐานฝั่งเซิร์ฟเวอร์ที่คุณต้องพึ่งพา JavaScript URLSearchParams ให้การซ่อนการเข้ารหัสรูปแบบที่ปลอดภัยบวกกับความซับซ้อน สร้าง URLSearchParams ผนวกรายการ เรียก toString() เพื่อรับ application/x-www-form-urlencoded ด้วยเครื่องหมายบวกที่เหมาะสม หรือสร้างสตริงการสืบค้นด้วย encodeURIComponent คุณได้รับ RFC 3986 %20 อย่าผสมแนวทาง สตริงการสืบค้นที่มีการบวกด้วยตนเองและ encodeURIComponent สร้างความกำกวม ผู้รับไม่สามารถแยกแยะได้ว่าบวกหมายถึงช่องว่างหรือบวกตามตัวอักษร แนวทางมาตรฐานได้รับการจัดการอย่างสม่ำเสมอ

URL มาตรฐานในปัจจุบัน — application/x-www-form-urlencoded เป็นซีเรียลไลเซอร์แยกต่างหากที่มีกฎของตัวเอง

โดยทั่วไป JSON API จะปฏิเสธเครื่องหมายบวกเป็นช่องว่าง โดยคาดหวัง %20 ต่อ RFC 3986 ไคลเอ็นต์ที่ส่งเครื่องหมายบวกล้มเหลวอย่างเงียบๆ: พารามิเตอร์หายไป การทดสอบ API ที่มีการเข้ารหัสทั้งสองแบบเผยให้เห็นมาตรฐานที่ยอมรับ URLSearchParams ใน JavaScript จัดการการเข้ารหัสแบบฟอร์ม URL ตัวเข้ารหัสและตัวถอดรหัสสร้าง RFC 3986 %20

HTML การส่งแบบฟอร์มจะจัดการการเข้ารหัสโดยอัตโนมัติ กรอบงานเซิร์ฟเวอร์ของคุณจะตัดสินใจว่าจะใช้กฎใด Rails, Django, PHP ทั้งหมดจะถือว่าบวกเป็นช่องว่างในข้อมูลแบบฟอร์มที่ได้รับโดยอัตโนมัติ แต่การสร้างสตริงการสืบค้นด้วยตนเองสำหรับปลายทางเดียวกันนั้นมีความสำคัญอย่างมาก การบวกที่อัปโหลดทำให้เกิดความกำกวม การปฏิบัติตามข้อกำหนดและพฤติกรรมของเซิร์ฟเวอร์ในโลกแห่งความเป็นจริงมีความแตกต่างกันเล็กน้อย เอกสารที่เป็นมาตรฐานที่ปลายทางของคุณคาดหวัง ทดสอบรูปแบบการเข้ารหัสทั้งสองแบบ รหัสการป้องกันจัดการทั้งสองได้อย่างสง่างาม

ตัวอย่างการทำงาน: ฟิลด์แบบฟอร์มเดียวกันที่เห็นเป็นสตริงการสืบค้นและเนื้อหาคำขอ - โดยมี + ในที่เดียวและ %20 ในอีกที่หนึ่ง

JavaScript URLSearchParams ใช้การเข้ารหัสแบบฟอร์ม: ช่องว่างจะกลายเป็นเครื่องหมายบวก ไม่ใช่ %20 URLSearchParams ใหม่ ({q: "hello world"}) สร้าง "q=hello+world" ไม่ใช่ "q=hello%20world" นี่คือกฎ application/x-www-form-urlencoded ในอดีตที่สร้างขึ้นใน JavaScript โดยเฉพาะ แต่การส่งสตริงนี้เป็นแบบสอบถามดิบไปยัง new URL จะเก็บ plus as plus; มีเพียง URLSearchParams เท่านั้นที่ถอดรหัสเป็นช่องว่าง ตัวสร้างมีความซื่อสัตย์ต่อสิ่งที่เห็น ความแตกต่างของเครื่องหมายบวกทำให้เกิดข้อบกพร่องทั่วไปเมื่อผสมฟังก์ชันไม่ถูกต้อง

URL Constructor และ encodeURIComponent เป็นเครื่องมือที่แตกต่างกัน encodeURIComponent เข้ารหัสเกือบทุกอย่าง ยกเว้นตัวอักษร ตัวเลข และ - _ ที่ไม่ได้สงวนไว้ ! ~ * ' ( ) มันถือว่าไม่มีบริบท URL ตัวสร้างแยกวิเคราะห์ URL จริงและใช้กฎ WHATWG ต่อส่วนประกอบ encodeURIComponent เปลี่ยน "hello/world" เป็น "hello%2Fworld"; ใหม่ URL เห็นเครื่องหมายทับเป็นตัวแยกเส้นทาง อินพุตเดียวกัน เอาต์พุตต่างกัน ใช้ encodeURIComponent เมื่อสร้าง URL โดยการต่อส่วนต่างๆ ใช้ URLSearchParams หรือ URL Constructor สำหรับ URL ที่สมบูรณ์หรือบางส่วน

เหตุใดจึงไม่สามารถแก้ไขได้ — เซิร์ฟเวอร์และไคลเอนต์หลายทศวรรษที่ขึ้นอยู่กับพฤติกรรมปัจจุบัน

กฎการเข้ารหัสเปอร์เซ็นต์พัฒนาจาก RFC 1738 (1994) ถึง RFC 2396 (1998) ถึง RFC 3986 (2005) แต่ละรุ่นชี้แจงความคลุมเครือ RFC 1738 เป็นแบบอนุรักษ์นิยม โดยปฏิบัติต่ออักขระที่ไม่ปลอดภัย เนื่องจากเว็บในยุคแรกๆ มีการรองรับอักขระที่จำกัด การปรับใช้ที่เป็นมาตรฐานบน UTF-8 การใช้งานมีความสอดคล้องกัน มาตรฐานต่อมาได้ผ่อนคลายข้อจำกัดเกี่ยวกับอักขระที่พิสูจน์ได้ว่าปลอดภัยทั่วทั้งระบบ ฉันทามติสมัยใหม่: UTF-8 ทุกที่ หน่วยงานมาตรฐานรักษาความเข้ากันได้แบบย้อนหลังอย่างเข้มงวด การแก้ไขจะต้องได้รับความร่วมมือจากทั่วโลก ซึ่งเป็นไปไม่ได้หลังจากผ่านไปสามทศวรรษ สองมาตรฐานอยู่ร่วมกันอย่างจงใจ

การทดสอบด้วยทั้งเครื่องหมายบวกและ %20 เผยให้เห็นสมมติฐานของเซิร์ฟเวอร์ บันทึกเซิร์ฟเวอร์แสดงสิ่งที่ไคลเอ็นต์ส่ง แบบฟอร์มใช้เครื่องหมายบวก; URL แบบกำหนดเองใช้ %20 เลือกตามบริบทและปฏิบัติตามเอกสารประกอบ API

สิ่งนี้ไม่ครอบคลุมถึง - หลายส่วน/form-data และ JSON เนื้อความ

การทดสอบการเข้ารหัสทั้งสองเผยให้เห็นพฤติกรรมของเซิร์ฟเวอร์ ส่ง a+b ทั้งสองทาง เซิร์ฟเวอร์ที่ใช้งานจริงจำนวนมากต้องการการเข้ารหัสแบบฟอร์ม API ที่ใหม่กว่าคาดหวัง %20 ทางเลือกของคุณขึ้นอยู่กับความคาดหวังของผู้รับ URLSearchParams จัดการการเข้ารหัสแบบฟอร์ม encodeURIComponent จัดการการเข้ารหัส RFC

อย่ารวมวิธีการเข้ารหัสเข้าด้วยกัน ค่าที่เข้ารหัสด้วย encodeURIComponent %2B จากนั้นส่งผ่านไปยัง URLSearchParams จะได้รับการเข้ารหัสซ้ำเป็น %252B การถอดรหัสครั้งเดียวจะให้ผล %2B แทนที่จะเป็นเครื่องหมายบวก อักขระจะกลายเป็นสตริงเปอร์เซ็นต์สองหกตามตัวอักษรแทนที่จะเป็นเครื่องหมายบวก ตรวจสอบขั้นตอนกลางในกระบวนการสร้างของคุณ การเข้ารหัสจะเกิดขึ้นเพียงครั้งเดียวต่อค่าเท่านั้น เอกสารที่ใช้การเข้ารหัสมาตรฐานไปป์ไลน์ของคุณ ทดสอบด้วยอักขระพิเศษ ได้แก่ เครื่องหมายบวก ช่องว่าง เครื่องหมายและ

ประเด็นสำคัญ: สองมาตรฐาน ทั้งคู่ถูกต้องในบริบท — อย่างไร URL ตัวเข้ารหัสและตัวถอดรหัสช่วยให้คุณ RFC 3986 แบบฟอร์มด้วย %20 สำหรับช่องว่างเพื่อให้คุณรู้ว่าคุณกำลังดูช่องไหน

การแยกบวกกับยี่สิบไม่ใช่จุดบกพร่องที่ต้องแก้ไข เป็นสิ่งประดิษฐ์ทางประวัติศาสตร์ของมาตรฐานในการแก้ปัญหาที่แตกต่างกันออกไป การแก้ไขจะต้องได้รับความร่วมมือจากทั่วโลก—จะเป็นไปไม่ได้หลังจากผ่านไปสามสิบปี หน่วยงานมาตรฐานจะไม่ทำลายเว็บย้อนหลัง RFC 3986 กฎของแบบฟอร์ม โครงสร้างเบราว์เซอร์ URL แต่ละรายการมีมาตรฐานและเหตุผล RFC 1866 การเข้ารหัสแบบฟอร์มและ RFC 3986 URI การเข้ารหัสให้บริการในเลเยอร์ที่แตกต่างกัน เข้ารหัสโดยเจตนารู้มาตรฐานของคุณ ทดสอบกับเพย์โหลดที่สมจริง

เลือกการเข้ารหัสตามบริบท ใช้แบบฟอร์มบวกตามมาตรฐาน HTML URI แบบกำหนดเองใช้ %20 ต่อ RFC 3986 API ระบุว่าควรคาดหวังสิ่งใด ปฏิบัติตามเอกสารประกอบหรือทดสอบทั้งสองอย่าง URL ตัวเข้ารหัสและตัวถอดรหัสแสดง RFC 3986 ต้องการการเข้ารหัสแบบฟอร์มหรือไม่? URLSearchParams ทำอย่างนั้น เครื่องมือไม่ผสมการเข้ารหัส การทำความเข้าใจมาตรฐานจะช่วยป้องกันความประหลาดใจ การเข้ารหัสที่ไม่สอดคล้องกันระหว่างเลเยอร์ทำให้เกิดการสูญเสียพารามิเตอร์เล็กน้อย การตัดทอน ข้อมูลเสียหาย มาตรฐานทั้งสองมีความถูกต้องในโดเมนของตน จงใจสมัครและจัดทำเอกสาร