“ ประเภทเนื้อหา: application / json; charset = utf-8” จริงๆหมายถึงอะไร


284

เมื่อฉันทำการร้องขอ POST ที่มีเนื้อหา JSON ไปยังบริการ REST ของฉันฉันรวมContent-type: application/json; charset=utf-8ไว้ในส่วนหัวของข้อความ หากไม่มีส่วนหัวนี้ฉันได้รับข้อผิดพลาดจากบริการ ฉันสามารถใช้งานได้Content-type: application/jsonโดยไม่ต้องมี;charset=utf-8ส่วนร่วม

ไม่ว่าสิ่งที่charset=utf-8ทำอย่างไร ฉันรู้ว่ามันระบุการเข้ารหัสตัวอักษร แต่บริการใช้งานได้ดีถ้าไม่มีมัน การเข้ารหัสนี้ จำกัด อักขระที่สามารถอยู่ในเนื้อหาของข้อความหรือไม่?



8
ตามการลงทะเบียนสื่อประเภทของ IANAapplication/jsonดูเหมือนว่าจะไม่ได้รับการสนับสนุนจากcharsetพารามิเตอร์ แต่อย่างใด
Uux

1
I know it specifies the character encoding but the service works fine without it."ทำงาน" ไม่ได้หมายความว่า "รหัส / การกำหนดค่าที่มีอยู่เป็นวิธีที่ถูกต้องที่สุดในการครอบคลุมทุกมุมของมุมที่จะทำสิ่งเดียว" ขึ้นอยู่กับอนุสัญญาและสมมติฐานทั้งหมดที่อาจไม่ทำงานภายใต้สถานการณ์อื่น สำหรับฉันเป็นการส่วนตัวฉันพยายามที่จะให้ชัดเจนที่สุดเท่าที่จะทำได้
WesternGun

3
การส่งพารามิเตอร์ "charset" ไม่ถูกต้องและไม่มีความหมาย ดู RFC 8259 ส่วนที่ 11 ประโยคสุดท้าย
Julian Reschke

คำตอบ:


283

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

Content-type: application/json; charset=utf-8กำหนดเนื้อหาให้อยู่ในรูปแบบ JSON เข้ารหัสในการเข้ารหัสอักขระ UTF-8 การกำหนดให้มีการเข้ารหัสค่อนข้างซ้ำซ้อนสำหรับ JSON เนื่องจากการเข้ารหัสเริ่มต้น (เท่านั้น) สำหรับ JSON คือ UTF-8 ดังนั้นในกรณีนี้เซิร์ฟเวอร์ที่รับมีความสุขที่รู้ว่ามันจัดการกับ JSON และสมมติว่าการเข้ารหัสเป็น UTF-8 ตามค่าเริ่มต้นนั่นคือสาเหตุที่มันทำงานได้โดยมีหรือไม่มีส่วนหัว

การเข้ารหัสนี้ จำกัด อักขระที่สามารถอยู่ในเนื้อหาของข้อความหรือไม่?

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


4
แน่นอนใน JSON คุณยังจะเป็นตัวแทนของอักขระที่ไม่ใช่ Latin1 \u20ACใช้ลำดับหนีเช่น
dan04

31
ตามมาตรฐานของ json คุณไม่ได้รับอนุญาตให้ใช้ latin1 สำหรับการเข้ารหัสเนื้อหา เนื้อหาของ JSON จะต้องเข้ารหัสเป็นยูนิโค้ดไม่ว่าจะเป็น UTF-8, UTF-16 หรือ UTF-32 (endian เล็กหรือใหญ่)
Daniel Luna Luna

20
ไม่มีพารามิเตอร์ charset ใน application / json
Julian Reschke

7
@DanielLuna ถูกต้องapplication/jsonจะต้องอยู่ในรูปแบบการแปลงucs อย่างใดอย่างหนึ่ง นอกจากนี้เนื่องจาก JSON สี่ไบต์แรกมี จำกัด คุณสามารถบอกได้เสมอว่าเป็น 8, 16, หรือ 32 และ endian-ness
Jason Coco

4
เหตุการณ์หากซ้ำซ้อนคุณอาจต้องการรวมcharset=utf-8เพื่อเหตุผลด้านความปลอดภัย: github.com/shieldfy/API-Security-Checklist/issues/25
manuc66

143

ในการยืนยันการอ้างสิทธิ์ของ @ หลอกว่าการเข้ารหัส JSON เริ่มต้นคือ UTF-8 ...

จากIETF RFC4627 :

ข้อความ JSON จะถูกเข้ารหัสใน Unicode การเข้ารหัสเริ่มต้นคือ UTF-8

เนื่องจากอักขระสองตัวแรกของข้อความ JSON จะเป็นอักขระ ASCII เสมอ [RFC0020] จึงเป็นไปได้ที่จะตรวจสอบว่าสตรีม octet คือ UTF-8, UTF-16 (BE หรือ LE) หรือ UTF-32 (BE หรือ LE) โดยดูที่รูปแบบของ nulls ในสี่ octets แรก

      00 00 00 xx  UTF-32BE
      00 xx 00 xx  UTF-16BE
      xx 00 00 00  UTF-32LE
      xx 00 xx 00  UTF-16LE
      xx xx xx xx  UTF-8

12
มันจะช่วยให้คิดเกี่ยวกับ JSON เป็นรูปแบบไบนารีไม่ใช่รูปแบบข้อความ
Sulthan

2
ตอนนี้ RFC4627 ล้าสมัยแล้วโดย RFC7159 ซึ่งระบุว่าค่ารูทอาจเป็นสตริง (ในทางตรงกันข้ามกับข้อกำหนดเดิม) วิธีนี้นำไปใช้งานได้อย่างไร สเป็คนั้นคลุมเครือในเรื่องนี้และเพิ่งบอกว่าอนุญาตให้ทำการเข้ารหัสได้สามแบบ แต่ไม่ใช่ว่าจะแยกความแตกต่างได้อย่างไร
Fabio Beltramini

4
@FabioBeltramini ข้อมูลด้านบนควรยังคงอยู่เนื่องจากสตริงใน JSON จะไม่มีอักขระตัวอักษรใด ๆ ที่เป็นโมฆะ (โมฆะใน JSON จะต้องมีการเข้ารหัสด้วยลำดับการหลีกเลี่ยงตัวเลข"\u0000")
thomasrutter

3
ที่จริงอักขระที่สองใน UTF-16xx อาจไม่มี NULL ในกรณีนั้น แต่มันยังคงเป็นไปได้ที่จะกำหนดการเข้ารหัสจากไบต์อื่น: xx 00 00 00ยังคงเป็น UTF-32LE และxx 00 xx xxยังคงเป็น UTF-16LE 00 xx xx xxยังคงเป็น UTF-16BE
thomasrutter

20

สังเกตได้ว่า IETF RFC4627ได้ถูกแทนที่โดยIETF RFC7158 ในส่วน [8.1] จะดึงข้อความที่อ้างถึงโดย @Drew ก่อนหน้าโดยพูดว่า:

Implementations MUST NOT add a byte order mark to the beginning of a JSON text.

การสันนิษฐานยังคงมีอยู่แม้ว่า json ที่ถูกต้องจะยังคงเริ่มต้นด้วยอักขระ ASCII สองตัว
Larsing

ตัวละครตัวหนึ่งเพราะตัวเลขเดียวเป็นไฟล์ JSON ที่ถูกต้อง
Nayuki

0

ฉันเห็นด้วยกับ @deceze แต่ฉันต้องการที่จะพัฒนาส่วนนี้"ฉันได้รับข้อผิดพลาดจากบริการ"ส่วนหนึ่งของคำถาม

เราได้รับข้อผิดพลาดประเภทนี้เป็นhttp 415

Http 415 ข้อผิดพลาดประเภทสื่อที่ไม่รองรับ

รหัสตอบสนองข้อผิดพลาดไคลเอนต์ Media Type HTTP 415 ที่ไม่สนับสนุนระบุว่าเซิร์ฟเวอร์ปฏิเสธที่จะยอมรับคำขอเนื่องจากรูปแบบของน้ำหนักบรรทุกอยู่ในรูปแบบที่ไม่รองรับ

ปัญหารูปแบบอาจเกิดจากการระบุเนื้อหาประเภทหรือการเข้ารหัสเนื้อหาที่ร้องขอหรือจากการตรวจสอบข้อมูลโดยตรง

ในคำอื่น ๆ เช่นที่เห็นในhttps://stackoverflow.com/a/22643964/914284ตัวอย่างนี้

  • เราต้องตั้งค่าประเภทเนื้อหาที่ถูกต้องและเราต้องยอมรับประเภทเนื้อหาที่ถูกต้องตามที่เห็นเพิ่มประเภทเนื้อหา: application / json และยอมรับ: application / json มิฉะนั้นจะถือว่าเป็นค่าเริ่มต้น

0

Dart http ของกระบวนการดำเนินการไบต์ขอบคุณที่ "charset = utf-8" ดังนั้นฉันมั่นใจว่าการใช้งานหลายอย่างออกมีการสนับสนุนนี้เพื่อหลีกเลี่ยง charset ทางเลือก "latin-1" เมื่ออ่านไบต์จากการตอบสนอง ในกรณีของฉันฉันสูญเสียรูปแบบทั้งหมดในสตริงเนื้อหาการตอบสนองดังนั้นฉันต้องทำการเข้ารหัสไบต์ด้วยตนเองเป็น utf8 หรือเพิ่มพารามิเตอร์ "inner" ส่วนหัวในการตอบสนอง API ของเซิร์ฟเวอร์ของฉัน


0

ผมใช้ HttpClient และได้รับหัวข้อการตอบสนองกลับมาพร้อมกับเนื้อหาประเภทของapplication/jsonผมหายไปตัวอักษรเช่นภาษาต่างประเทศหรือสัญลักษณ์ที่ใช้มาตั้งแต่ Unicode HttpClient เป็นค่าเริ่มต้นให้กับISO-8859-1 ดังนั้นชัดเจนที่สุดเท่าที่จะทำได้ตามที่ระบุไว้โดย @WesternGun เพื่อหลีกเลี่ยงปัญหาที่อาจเกิดขึ้น

ไม่มีทางที่จะจัดการได้เนื่องจากเซิร์ฟเวอร์ไม่ได้จัดการกับชุดอักขระส่วนหัวที่ร้องขอ ( method.setRequestHeader("accept-charset", "UTF-8");) สำหรับฉันและฉันต้องดึงข้อมูลการตอบกลับเป็นไบต์ที่วาดและแปลงเป็นสตริงโดยใช้ UTF-8 ดังนั้นจึงขอแนะนำให้ชัดเจนและหลีกเลี่ยงการสันนิษฐานว่าเป็นค่าเริ่มต้น

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