การเข้ารหัสอักขระ JSON - UTF-8 ได้รับการสนับสนุนอย่างดีจากเบราว์เซอร์หรือฉันควรใช้ลำดับการหลีกเลี่ยงตัวเลข


91

ฉันกำลังเขียนเว็บเซอร์ที่ใช้ json เพื่อแสดงถึงทรัพยากรและฉันรู้สึกติดขัดเล็กน้อยเกี่ยวกับวิธีที่ดีที่สุดในการเข้ารหัส json การอ่าน json rfc ( http://www.ietf.org/rfc/rfc4627.txt ) เป็นที่ชัดเจนว่าการเข้ารหัสที่ต้องการคือ utf-8 แต่ rfc ยังอธิบายกลไกการหลีกเลี่ยงสตริงสำหรับการระบุอักขระ ฉันคิดว่าโดยทั่วไปจะใช้เพื่อหลีกเลี่ยงอักขระที่ไม่ใช่ ascii ดังนั้นจึงทำให้ utf-8 เป็นผลลัพธ์ที่ถูกต้อง ascii

สมมติว่าฉันมีสตริง json ที่มีอักขระ Unicode (จุดรหัส) ที่ไม่ใช่ ascii บริการเว็บของฉันควรเข้ารหัสเพียง utf-8 แล้วส่งคืนหรือควรหลีกเลี่ยงอักขระที่ไม่ใช่ ascii ทั้งหมดและส่งคืน ascii บริสุทธิ์

ฉันต้องการให้เบราว์เซอร์สามารถเรียกใช้ผลลัพธ์โดยใช้ jsonp หรือ eval มีผลต่อการตัดสินใจหรือไม่? ฉันขาดความรู้เกี่ยวกับการรองรับจาวาสคริปต์ของเบราว์เซอร์ต่างๆสำหรับ utf-8

แก้ไข: ฉันต้องการชี้แจงว่าความกังวลหลักของฉันเกี่ยวกับวิธีการเข้ารหัสผลลัพธ์นั้นเกี่ยวกับการจัดการผลลัพธ์ของเบราว์เซอร์จริงๆ สิ่งที่ฉันอ่านระบุว่าเบราว์เซอร์อาจไวต่อการเข้ารหัสเมื่อใช้ JSONP โดยเฉพาะ ฉันไม่พบข้อมูลที่ดีเกี่ยวกับเรื่องนี้ดังนั้นฉันจะต้องเริ่มทำการทดสอบเพื่อดูว่าเกิดอะไรขึ้น ตามหลักการแล้วฉันต้องการหลีกเลี่ยงอักขระเพียงไม่กี่ตัวที่จำเป็นและเพียงแค่ utf-8 เข้ารหัสผลลัพธ์

คำตอบ:


89

ข้อกำหนด JSON ต้องการการสนับสนุน UTF-8 โดยตัวถอดรหัส เป็นผลให้ตัวถอดรหัส JSON ทั้งหมดสามารถจัดการ UTF-8 ได้เช่นเดียวกับที่สามารถจัดการกับลำดับการหลีกเลี่ยงตัวเลขได้ นอกจากนี้ยังเป็นกรณีสำหรับล่าม Javascript ซึ่งหมายความว่า JSONP จะจัดการ JSON ที่เข้ารหัส UTF-8 ด้วยเช่นกัน

ความสามารถสำหรับตัวเข้ารหัส JSON ในการใช้ลำดับการหลีกเลี่ยงตัวเลขแทนจะช่วยให้คุณมีทางเลือกมากขึ้น เหตุผลหนึ่งที่คุณอาจเลือกลำดับการหลีกเลี่ยงตัวเลขคือถ้ากลไกการขนส่งอยู่ระหว่างข้อมูลตัวเข้ารหัสและตัวถอดรหัสที่ตั้งใจไว้นั้นไม่ปลอดภัยแบบไบนารี

เหตุผลที่คุณอาจต้องการใช้ลำดับหนีตัวเลขก็คือการป้องกันไม่ให้ตัวอักษรบางอย่างที่ปรากฏในกระแสเช่น<, &และ"ซึ่งอาจตีความได้ว่า HTML ลำดับหากรหัส JSON ถูกวางไว้โดยไม่ต้องหลบหนีเข้าไปใน HTML หรือเบราว์เซอร์ผิดตีความว่าเป็น HTML . สิ่งนี้สามารถป้องกันการแทรก HTML หรือการเขียนสคริปต์ข้ามไซต์ได้ (หมายเหตุ: อักขระบางตัวต้องถูก Escape ใน JSON รวมถึง"และ\)

เฟรมเวิร์กบางอย่างรวมถึงการใช้ JSON ของ PHP จะทำลำดับการหลีกเลี่ยงตัวเลขที่ด้านตัวเข้ารหัสสำหรับอักขระใด ๆ ที่อยู่นอก ASCII เสมอ สิ่งนี้มีไว้เพื่อความเข้ากันได้สูงสุดกับกลไกการขนส่งที่ จำกัด และสิ่งที่คล้ายกัน อย่างไรก็ตามไม่ควรตีความว่าเป็นการบ่งชี้ว่าตัวถอดรหัส JSON มีปัญหากับ UTF-8

ดังนั้นฉันเดาว่าคุณสามารถตัดสินใจได้ว่าจะใช้แบบนี้:

  • เพียงใช้ UTF-8 เว้นแต่วิธีการจัดเก็บหรือการขนส่งระหว่างตัวเข้ารหัสและตัวถอดรหัสจะไม่ปลอดภัยแบบไบนารี

  • มิฉะนั้นให้ใช้ลำดับการหลีกเลี่ยงตัวเลข


1
"ตัวถอดรหัส JSON ทั้งหมดสามารถจัดการ UTF-8 ได้" แม้ว่าจะเป็นจริงสำหรับเบราว์เซอร์เพียงเพราะมาตรฐานกำหนดไม่ได้หมายความว่าการถอดรหัสซอฟต์แวร์ทั้งหมด JSON รองรับ UTF-8
Michael Mior

7
"ตัวถอดรหัส JSON ทั้งหมดสามารถจัดการ UTF-8 ได้" นั้นเป็นความจริงอย่างแท้จริง หากสิ่งใดไม่สามารถยอมรับ UTF-8 ได้แสดงว่าไม่ใช่ตัวถอดรหัส JSON อาจคล้ายกับตัวถอดรหัส JSON แต่ไม่ใช่ตัวถอดรหัสเดียว
thomasrutter

ฉันเดาว่าขึ้นอยู่กับความหมายของตัวถอดรหัส JSON ที่คุณใช้ แต่จุดที่ยุติธรรม :)
Michael Mior

เหตุผลที่ RFC 8259 ระบุว่าการสนับสนุน UTF-8 เป็นข้อบังคับนั้นเป็นสิ่งที่มาตรฐานโลกกำหนดไว้ ข้อกำหนดที่ล้าสมัยก่อนหน้านี้กำหนดสตริงเป็น Unicode แต่ไม่ได้ระบุว่าเข้ารหัสใด การใช้งานที่เป็นมาตรฐานบน UTF-8 อยู่ดีและข้อมูลจำเพาะที่อัปเดตสะท้อนให้เห็น
thomasrutter

ไม่ได้ระบุการสนับสนุน UTF-8 เป็นข้อบังคับใน RFC นั้นสำหรับซอฟต์แวร์ใด ๆ เท่าที่ฉันสามารถบอกได้ การกล่าวถึง UTF-8 เพียงอย่างเดียวคือต้องใช้เป็นการเข้ารหัสสำหรับ JSON ที่แลกเปลี่ยนนอกระบบปิด นี่ไม่ได้หมายความว่าตัวถอดรหัส JSON ทั้งหมด (ภาษาที่ไม่ได้ใช้ใน RFC) ต้องรองรับ UTF-8
Michael Mior

17

ฉันมีปัญหาที่นั่น เมื่อ I JSON เข้ารหัสสตริงด้วยอักขระเช่น "é" เบราว์เซอร์ทุกตัวจะส่งคืน "é" เหมือนกันยกเว้น IE ซึ่งจะส่งคืน "\ u00e9"

จากนั้นด้วย PHP json_decode () จะล้มเหลวหากพบ "é" ดังนั้นสำหรับ Firefox, Opera, Safari และ Chrome ฉันจะเรียก utf8_encode () ก่อน json_decode ()

หมายเหตุ: จากการทดสอบของฉัน IE และ Firefox กำลังใช้ออบเจ็กต์ JSON ดั้งเดิมเบราว์เซอร์อื่น ๆ ใช้ json2.js


10
คุณอาจหมายutf8_encode(), php.net/manual/en/function.utf8-encode.php
Binyamin

4
หาก IE ไม่สามารถถอดรหัสได้แสดงว่าเป็นบั๊กของตัวถอดรหัส JSON ที่คุณใช้อยู่ ตัวถอดรหัส JSON ทั้งหมดต้องถอดรหัสรูปแบบที่เข้ารหัสได้สำเร็จมิฉะนั้นจะไม่ใช่ตัวถอดรหัส JSON สำหรับปัญหาของคุณเกี่ยวกับ json_decode () ที่มีé unescaped เป็นไปได้ว่าข้อความที่คุณกำลังป้อนนั้นไม่ใช่ UTF-8 ตัวถอดรหัส JSON จะถือว่า UTF-8 เสมอแม้กระทั่งการใช้งาน PHP แม้ว่าโดยปกติแล้ว PHP จะไม่ถือว่า UTF-8 ในฟังก์ชันอื่น ๆ มีการเข้ารหัสอักขระอื่น ๆ ซึ่งอาจรวมถึงéที่ไม่ใช้ Escape และมีลักษณะเหมือนกันบนหน้าจอ แต่ไม่ใช่ UTF-8 การเข้ารหัสในรูปแบบ \ uXXXX เป็นวิธีแก้ปัญหานี้
thomasrutter

เพียงแค่พูดว่า: JSON สามารถเข้ามาในการเข้ารหัส Unicode ได้ตามกฎหมาย (UTF-8, UTF-16 BE / LE, UTF32 BE / LE โดยมีหรือไม่มีเครื่องหมายคำสั่งไบต์ก็ได้) และเนื่องจาก ASCII เป็นชุดย่อยของ UTF-8 จึงสามารถมาใน ASCII ได้ ตัวอย่างเช่นตัวแยกวิเคราะห์ยอมรับ UTF-32 หรือไม่ฉันไม่ทราบ
gnasher729

1
ถูกต้องและตัวแยกวิเคราะห์ไม่จำเป็นต้องรองรับสิ่งอื่นใดนอกจาก UTF-8 จากข้อมูลจำเพาะ: "ข้อความ JSON จะเข้ารหัสเป็น UTF-8, UTF-16 หรือ UTF-32 การเข้ารหัสเริ่มต้นคือ UTF-8 และข้อความ JSON ที่เข้ารหัสใน UTF-8 จะทำงานร่วมกันได้ในแง่ที่ว่าจะ สามารถอ่านได้สำเร็จตามจำนวนการใช้งานสูงสุดมีการใช้งานจำนวนมากที่ไม่สามารถอ่านข้อความในการเข้ารหัสอื่น ๆ ได้สำเร็จ (เช่น UTF-16 และ UTF-32) การใช้งานต้องไม่เพิ่มเครื่องหมายลำดับไบต์ที่จุดเริ่มต้นของข้อความ JSON "
thomasrutter

@thomasrutter สเป็คที่คุณยกมามันเก่า ข้อมูลจำเพาะปัจจุบันกล่าวว่า " ข้อความ JSON แลกเปลี่ยนระหว่างระบบที่ไม่ได้เป็นส่วนหนึ่งของระบบนิเวศที่ปิดจะต้องเข้ารหัสโดยใช้ UTF-8 รายละเอียดก่อนหน้า JSON ได้ไม่จำเป็นต้องใช้ UTF-8 เมื่อส่งข้อความ JSON อย่างไรก็ตามส่วนใหญ่.. ของการใช้งานซอฟต์แวร์ที่ใช้ JSON ได้เลือกที่จะใช้การเข้ารหัส UTF-8 ในขอบเขตที่เป็นการเข้ารหัสเดียวที่สามารถทำงานร่วมกันได้การใช้งานต้องไม่เพิ่มเครื่องหมายลำดับไบต์ (U + FEFF) ที่จุดเริ่มต้นของการส่งผ่านเครือข่าย ข้อความ JSON "
Remy Lebeau

12

ASCII ไม่ได้อยู่ในนั้นอีกต่อไป การใช้การเข้ารหัส UTF-8 หมายความว่าคุณไม่ได้ใช้การเข้ารหัส ASCII สิ่งที่คุณควรใช้กลไกการหลบหนีคือสิ่งที่ RFC พูด:

อักขระ Unicode ทั้งหมดอาจอยู่ในเครื่องหมายคำพูดยกเว้นอักขระที่ต้องใช้ Escape: เครื่องหมายคำพูด, reverse solidus และอักขระควบคุม (U + 0000 ถึง U + 001F)


1
หากอ่านคำพูดที่คุณให้มาคุณจะเห็นว่าคุณไม่จำเป็นต้องใช้อักขระ Unicode ทั้งหมดมีเพียงอักขระพิเศษไม่กี่ตัวเท่านั้น แต่คุณจะต้องเข้ารหัสผลลัพธ์ (ควรใช้ utf-8) ดังนั้นคำถามคือ: "ทำไมต้องใช้อักขระ Unicode ปกติถ้าคุณกำลังเข้ารหัส utf-8"
schickb

นอกจากนี้สตริงที่เข้ารหัส ascii ยังเป็นชุดย่อยที่แท้จริงของ utf-8 ถ้าฉันใช้การหลีกเลี่ยงของ json สำหรับอักขระที่ไม่ใช่ ascii ทั้งหมดผลลัพธ์จะเป็น ascii - ดังนั้นจึงเป็น utf-8 ไลบรารี json ต่างๆ (เช่น python simplejson) มีโหมดในการบังคับผลลัพธ์ ascii ฉันคิดว่ามีเหตุผลเช่นบางทีการดำเนินการในเบราว์เซอร์
schickb

เมื่อคุณรบกวนการหลีกเลี่ยงอักขระ Unicode ปกติจะอยู่ในบริบทที่เป็นอักขระเมตาเช่นสตริง (ส่วน RFC ที่ฉันยกมานั้นเกี่ยวกับสตริงขออภัยไม่ชัดเจนเกี่ยวกับเรื่องนี้) คุณไม่จำเป็นต้องทำเอาต์พุต ASCII ตลอดเวลา ฉันคิดว่านั่นเป็นมากกว่าสำหรับการดีบักกับเบราว์เซอร์ที่เสีย
วุ่นวาย

7

ฉันกำลังเผชิญกับปัญหาเดียวกัน มันใช้ได้กับฉัน โปรดตรวจสอบสิ่งนี้

json_encode($array,JSON_UNESCAPED_UNICODE);

ควรสังเกตว่าข้างต้นเป็น PHP เนื่องจากคำถามไม่ได้เจาะจง PHP และพูดถึงเฉพาะบริการเว็บซึ่งอาจไม่ใช้ PHP (เนื่องจากผู้อ่านรุ่นเก่าของเราอาจยังจำได้…)
ntninja

1

การอ่าน json rfc ( http://www.ietf.org/rfc/rfc4627.txt ) เป็นที่ชัดเจนว่าการเข้ารหัสที่ต้องการคือ utf-8

FYI, RFC 4627 ไม่ใช่ข้อมูลจำเพาะ JSON อย่างเป็นทางการอีกต่อไป มันถูกยกเลิกในปี 2014 โดยRFC 7159ซึ่งถูกยกเลิกในปี 2017 โดยRFC 8259ซึ่งเป็นข้อมูลจำเพาะปัจจุบัน

RFC 8259 รัฐ:

8.1. การเข้ารหัสอักขระ

ข้อความ JSON ที่แลกเปลี่ยนระหว่างระบบที่ไม่ได้เป็นส่วนหนึ่งของระบบนิเวศแบบปิดต้องเข้ารหัสโดยใช้ UTF-8 [RFC3629][RFC3629]

ข้อกำหนดก่อนหน้าของ JSON ไม่จำเป็นต้องใช้ UTF-8 เมื่อส่งข้อความ JSON อย่างไรก็ตามการใช้งานซอฟต์แวร์ที่ใช้ JSON ส่วนใหญ่เลือกที่จะใช้การเข้ารหัส UTF-8 ในขอบเขตที่เป็นการเข้ารหัสเพียงอย่างเดียวที่สามารถทำงานร่วมกันได้

การนำไปใช้งานต้องไม่เพิ่มเครื่องหมายลำดับไบต์ (U + FEFF) ที่จุดเริ่มต้นของข้อความ JSON ที่ส่งผ่านเครือข่าย เพื่อประโยชน์ของความสามารถในการทำงานร่วมกันการใช้งานที่แยกวิเคราะห์ข้อความ JSON อาจละเว้นการมีอยู่ของเครื่องหมายคำสั่งไบต์แทนที่จะถือว่าเป็นข้อผิดพลาด


0

ฉันมีปัญหาคล้าย ๆ กันกับé char ... ฉันคิดว่าความคิดเห็น "เป็นไปได้ว่าข้อความที่คุณให้อาหารไม่ใช่ UTF-8" อาจใกล้เคียงกับเครื่องหมายที่นี่ ฉันรู้สึกว่าการเรียงค่าเริ่มต้นในอินสแตนซ์ของฉันเป็นอย่างอื่นจนกว่าฉันจะรู้และเปลี่ยนเป็น utf8 ... ปัญหาคือข้อมูลมีอยู่แล้วดังนั้นไม่แน่ใจว่ามันแปลงข้อมูลหรือไม่เมื่อฉันเปลี่ยนแสดงได้ดีใน mysql โต๊ะทำงาน ผลลัพธ์สุดท้ายคือ php จะไม่ json เข้ารหัสข้อมูลเพียงส่งคืนเท็จ ไม่สำคัญว่าคุณใช้เบราว์เซอร์ใดเป็นเซิร์ฟเวอร์ที่ทำให้เกิดปัญหาของฉัน php จะไม่แยกวิเคราะห์ข้อมูลเป็น utf8 หากมีถ่านนี้อยู่ เช่นเดียวกับที่ฉันบอกว่าไม่แน่ใจว่าเกิดจากการแปลง schema เป็น utf8 หลังจากมีข้อมูลหรือเป็นเพียงจุดบกพร่องของ php ในกรณีนี้ให้ใช้json_encode(utf8_encode($string));

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.