jQuery จะไม่แยกวิเคราะห์ JSON ของฉันจากแบบสอบถาม AJAX


88

ฉันมีปัญหาในการแยกวิเคราะห์ข้อมูล JSON ที่ส่งคืนจากเซิร์ฟเวอร์ของฉันโดยใช้ jQuery.ajax ()

ในการดำเนินการ AJAX ฉันใช้:

$.ajax({
  url: myUrl,
  cache: false,
  dataType: "json",
  success: function(data){
    ...
  },
  error: function(e, xhr){
    ...
  }
});  

และถ้าฉันส่งคืนอาร์เรย์ของรายการมันก็ใช้ได้ดี:

[ { title: "One", key: "1" }, { title: "Two", key: "2" } ]

ฟังก์ชันความสำเร็จถูกเรียกและรับวัตถุที่ถูกต้อง

อย่างไรก็ตามเมื่อฉันพยายามส่งคืนวัตถุชิ้นเดียว:

{ title: "One", key: "1" } 

ฟังก์ชันข้อผิดพลาดถูกเรียกใช้และ xhr มี 'parsererror' ฉันได้ลองห่อ JSON ไว้ในวงเล็บบนเซิร์ฟเวอร์ก่อนที่จะส่งมันไปตามสาย แต่ก็ไม่แตกต่างกัน แต่ถ้าฉันวางเนื้อหาลงในสตริงใน Javascript แล้วใช้ฟังก์ชัน eval () มันจะประเมินได้อย่างสมบูรณ์แบบ

มีความคิดอะไรที่ฉันทำผิด?

แอนโธนี่


ที่เกี่ยวข้อง: stackoverflow.com/questions/631418/…
Michael Myers

คำตอบ:


72

เซิร์ฟเวอร์ของคุณส่งข้อมูลเป็น Content-Type "*/json"หรือไม่ หากไม่เป็นเช่นนั้นให้แก้ไขส่วนหัวการตอบกลับตามนั้น การส่ง"application/json"จะดีเช่น


ประการที่สองการคาดเดานี้มีปัญหาเดียวกันหนึ่งครั้งและได้เรียนรู้ว่าน่าแปลกใจที่ฉันใช้ละครใบ้ผิดประเภท หากคุณกำลังทดสอบผ่าน localhost บน windows โปรดระวังเรื่องนี้ให้มาก ลองอัปโหลดที่ใดที่หนึ่งแล้วทดสอบอีกครั้ง หากคุณต้องการให้มันทำงานบน localhost คุณต้องปลอมแปลงคำขอจริงๆ
Josh

51

ตามข้อกำหนดของjson.org การส่งคืนของคุณไม่ถูกต้อง ชื่อจะถูกยกมาเสมอดังนั้นคุณควรกลับมา

{ "title": "One", "key": "1" }

และ

[ { "title": "One", "key": "1" }, { "title": "Two", "key": "2" } ]

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


2
อันที่จริงใน jQuery 1.4 (ตัวอย่าง) { key: 'val' }ไม่ใช่ JSON ที่ถูกต้อง
rfunduk

34

สตริง JSON ถูกรวมไว้ด้วยเครื่องหมายคำพูดคู่ อัญประกาศเดี่ยวไม่ใช่สิ่งทดแทนที่ถูกต้อง

{"who": "Hello World"}

ถูกต้อง แต่นี่ไม่ใช่ ...

{'who': 'Hello World'}

แม้ว่าจะไม่ใช่ปัญหาของ OP แต่คิดว่ามันคุ้มค่าที่จะสังเกตเห็นคนอื่น ๆ ที่มาที่นี่


30

ปัญหานี้มักเกิดจากคำขอของคุณได้รับการแสดงละครใบ้ผิดประเภท เมื่อพัฒนาบนคอมพิวเตอร์ของคุณเองบางครั้งคุณไม่ได้รับประเภทละครใบ้ที่เหมาะสมจาก "เซิร์ฟเวอร์" ซึ่งเป็นคอมพิวเตอร์ของคุณเอง ฉันพบปัญหานี้หนึ่งครั้งเมื่อพัฒนาโดยการเปิดไฟล์ที่จัดเก็บในเครื่องในเบราว์เซอร์ (เช่น url คือ "c: /project/test.html")

ลองใช้คุณสมบัติ beforeSend เพื่อเพิ่มฟังก์ชันการเรียกกลับที่แทนที่ประเภท mime สิ่งนี้จะหลอกให้โค้ดจัดการกับ json แม้ว่าเซิร์ฟเวอร์จะส่ง mime ผิดประเภทและได้รับรหัสการโทรของคุณก็ตาม โค้ดตัวอย่างบางส่วนอยู่ด้านล่าง

ประเภทละครใบ้ที่เหมาะสมคือ application / json ตามคำถามนี้แต่ฉันรู้ว่าแอปพลิเคชัน / j-son ใช้งานได้เมื่อฉันลองใช้ (ตอนนี้หลายปีก่อน) คุณควรลองใช้ application / json ก่อน

var jsonMimeType = "application/json;charset=UTF-8";
$.ajax({
 type: "GET",
 url: myURL,
 beforeSend: function(x) {
  if(x && x.overrideMimeType) {
   x.overrideMimeType(jsonMimeType);
  }
 },
 dataType: "json",
 success: function(data){
  // do stuff...
 }
});

แค่อยากจะบอกว่า beforeSend คำแนะนำที่คุณแนะนำได้ผลสำหรับฉัน !! การโทร ajax ของฉันใช้งานได้ดีในซาฟารีและโครเมี่ยม แต่ไม่ใช่ Firefox ทันทีที่ฉันเพิ่ม beforeSend แล้ว Firefox ก็จะปิดทันที ว้าว!! ขอบคุณ !!
Karmen Blake

7

ฉันมีปัญหานี้และใช้ไปเล็กน้อย

eval('('+data+')')

เพื่อรับข้อมูลที่ส่งคืนในวัตถุ แต่ต่อมามีปัญหาอื่น ๆ ที่ทำให้เกิดข้อผิดพลาด 'หายไป) ในวงเล็บ' และพบว่า jQuery มีฟังก์ชันเฉพาะสำหรับการประเมินสตริงสำหรับโครงสร้าง json:

$.parseJSON(data)

ควรทำเคล็ดลับ นี่คือนอกเหนือจากการมีสตริง json ของคุณในรูปแบบที่เหมาะสมแน่นอน ..


6

หากคุณกำลังสะท้อนการตอบกลับ json และส่วนหัวของคุณไม่ตรงกับ * / json คุณสามารถใช้ api ที่สร้างขึ้นใน jQuery.parseJSON เพื่อแยกวิเคราะห์การตอบสนอง

response = '{"name":"John"}';
var obj = jQuery.parseJSON(response);
alert( obj.name === "John" );

4
{ title: "One", key: "1" }

ไม่ได้เป็นอย่างที่คุณคิด. ในฐานะนิพจน์มันเป็น Object literal แต่เป็นคำสั่ง:

{                // new block
    title:       // define a label called 'title' for goto statements
        "One",   // statement: the start of an expression which will be ignored
        key:     // ...er, what? you can't have a goto label in the middle of an expression
                 // ERROR

น่าเสียดายที่ eval () ไม่ได้ให้วิธีระบุว่าคุณกำลังให้คำสั่งหรือนิพจน์และมีแนวโน้มที่จะเดาผิด

วิธีแก้ปัญหาตามปกติคือการใส่อะไรก็ได้ในวงเล็บก่อนส่งไปยังฟังก์ชัน eval () คุณบอกว่าคุณได้ลองทำบนเซิร์ฟเวอร์ ... เห็นได้ชัดว่ายังไม่ผ่าน ควรกันน้ำที่จะพูดในตอนท้ายของไคลเอ็นต์สิ่งที่ได้รับการตอบสนอง XMLHttpRequest:

eval('('+responseText+')');

แทน:

eval(responseText);

ตราบใดที่คำตอบนั้นเป็นนิพจน์ไม่ใช่คำสั่ง (เช่นไม่มีอนุประโยคที่คั่นด้วยอัฒภาคหรือขึ้นบรรทัดใหม่หลายตัว)


ฉันคิดว่า jQuery เพิ่มวงเล็บโดยอัตโนมัติเมื่อประมวลผลข้อมูลคำขอ
strager

2
คำตอบนี้มีประโยชน์กับฉันมากเพราะฉันไม่เคยเข้าใจเลยว่าทำไมคนถึงห่อ JSON ไว้ในวงเล็บ
Andrey Tarantsov


2

หากคุณใช้ ASP.NET Web Services โดยใช้ jQuery ตรวจสอบให้แน่ใจว่าคุณมีสิ่งต่อไปนี้รวมอยู่ใน web.config ของคุณ:

<webServices>
    <protocols>
        <add name="HttpGet"/>
        <add name="HttpPost"/>
    </protocols>
</webServices>

2

ฉันมีปัญหาคล้ายกันกับที่ Firefox 3.5 ทำงานได้ดีและแยกวิเคราะห์ข้อมูล JSON ของฉัน แต่ Firefox 3.0.6 ส่งคืนการแยกวิเคราะห์ ปรากฎว่ามันเป็นพื้นที่ว่างที่จุดเริ่มต้นของ JSON ซึ่งทำให้ Firefox 3.0.6 เกิดข้อผิดพลาด การลบพื้นที่ว่างแก้ไขมัน


2

เทคนิค "eval ()" และ "JSON.parse ()" ใช้รูปแบบที่ไม่ซ้ำกัน

  • ด้วย "EVAL ()" วงเล็บจะต้อง
  • ด้วย "JSON.parse ()" วงเล็บจะต้องห้าม

ระวังมีฟังก์ชัน "stringify ()" ที่สร้างรูปแบบ "eval" สำหรับ ajax คุณควรใช้เฉพาะรูปแบบ JSON

แม้ว่า "eval" จะรวมภาษา JavaScript ทั้งหมดไว้ด้วยกัน แต่ JSON จะใช้ภาษาเพียงบางส่วนเท่านั้น ในบรรดาโครงสร้างในภาษา JavaScript ที่ "eval" ต้องรับรู้คือ"Block statement" (aka "compound statement") ; ซึ่งเป็นวงเล็บปีกกาคู่หรือหยิก "{}" ที่มีข้อความอยู่ข้างใน แต่ยังใช้วงเล็บปีกกาในไวยากรณ์ของตัวอักษรของวัตถุ การตีความแตกต่างกันไปตามบริบทที่โค้ดปรากฏ บางสิ่งอาจดูเหมือนเป็นอ็อบเจกต์ลิเทอรัลสำหรับคุณ แต่ "eval" จะเห็นว่าเป็นคำสั่งผสม

ในภาษา JavaScript ตัวอักษรออบเจ็กต์จะอยู่ทางด้านขวาของงาน

var myObj = { ...some..code..here... };

วัตถุตามตัวอักษรไม่ได้เกิดขึ้นเอง

{ ...some..code..here... }   // this looks like a compound statement

ย้อนกลับไปที่คำถามเดิมของ OP ซึ่งถามในปี 2008 เขาถามว่าทำไมสิ่งต่อไปนี้จึงล้มเหลวใน "eval ()":

{ title: "One", key: "1" }

คำตอบคือมันดูเหมือนคำสั่งประกอบ ในการแปลงเป็นวัตถุคุณต้องใส่ไว้ในบริบทที่คำสั่งผสมเป็นไปไม่ได้ ซึ่งทำได้โดยใส่วงเล็บรอบ ๆ

( { title: "One", key: "1" } )    // not a compound statment, so must be object literal

OP ยังถามว่าเหตุใดคำสั่งที่คล้ายกันจึงประสบความสำเร็จในการประเมิน:

[ { title: "One", key: "1" }, { title: "Two", key: "2" } ]

คำตอบเดียวกันนี้ใช้ได้ - วงเล็บปีกกาอยู่ในบริบทที่ไม่สามารถใช้คำสั่งผสมได้ นี่คือบริบทอาร์เรย์ " [...]" และอาร์เรย์สามารถมีออบเจ็กต์ได้ แต่ไม่สามารถมีคำสั่งได้

ซึ่งแตกต่างจาก "eval ()" ตรงที่ JSON มีขีดความสามารถที่ จำกัด มาก ข้อ จำกัด คือเจตนา ผู้ออกแบบ JSON ตั้งใจให้เป็นชุดย่อยของ JavaScript แบบเรียบง่ายโดยใช้เฉพาะไวยากรณ์ที่ปรากฏทางด้านขวามือของงาน ดังนั้นหากคุณมีโค้ดที่แยกวิเคราะห์ใน JSON ได้อย่างถูกต้อง ...

var myVar = JSON.parse("...some...code...here...");

... นั่นหมายความว่ามันจะแยกวิเคราะห์ทางขวามือของงานเช่นนี้ด้วย ..

var myVar = ...some..code..here... ;

แต่นั่นไม่ใช่ข้อ จำกัด เพียงอย่างเดียวใน JSON ข้อกำหนดภาษา BNF สำหรับ JSONเป็นเรื่องง่ายมาก ตัวอย่างเช่นไม่อนุญาตให้ใช้เครื่องหมายคำพูดเดี่ยวเพื่อระบุสตริง (เช่น JavaScript และ Perl do) และไม่มีวิธีแสดงอักขระเดี่ยวเป็นไบต์ (เช่น 'C') น่าเสียดายที่ไม่อนุญาตให้แสดงความคิดเห็น (ซึ่งจะดีมากเมื่อสร้างไฟล์กำหนดค่า) ข้อดีของข้อ จำกัด เหล่านี้คือการแยกวิเคราะห์ JSON นั้นรวดเร็วและไม่มีโอกาสในการแทรกโค้ด (ภัยคุกคามด้านความปลอดภัย)

เนื่องจากข้อ จำกัด เหล่านี้ JSON จึงไม่ใช้วงเล็บ ดังนั้นวงเล็บในสตริง JSON จึงเป็นอักขระที่ไม่ถูกต้อง

ใช้รูปแบบ JSON กับ ajax เสมอด้วยเหตุผลต่อไปนี้:

  • ไปป์ไลน์ ajax ทั่วไปจะถูกกำหนดค่าสำหรับ JSON
  • การใช้ "eval ()" จะถูกวิพากษ์วิจารณ์ว่าเป็นความเสี่ยงด้านความปลอดภัย

ดังตัวอย่างของไปป์ไลน์ของ ajax ให้พิจารณาโปรแกรมที่เกี่ยวข้องกับเซิร์ฟเวอร์โหนดและไคลเอ็นต์ jQuery โปรแกรมไคลเอนต์ที่ใช้โทร jQuery $.ajax({dataType:'json',...etc.});มีแบบฟอร์ม JQuery สร้างออบเจ็กต์ jqXHR เพื่อใช้ในภายหลังจากนั้นแพ็กเกจและส่งคำขอที่เกี่ยวข้อง เซิร์ฟเวอร์ยอมรับคำขอประมวลผลและพร้อมที่จะตอบสนอง โปรแกรมเซิร์ฟเวอร์จะเรียกใช้เมธอดres.json(data)เพื่อทำแพ็กเกจและส่งการตอบกลับ กลับไปที่ฝั่งไคลเอ็นต์ jQuery ยอมรับการตอบสนองปรึกษาอ็อบเจ็กต์ jqXHR ที่เกี่ยวข้องและประมวลผลข้อมูลที่จัดรูปแบบ JSON ทั้งหมดนี้ใช้งานได้โดยไม่ต้องมีการแปลงข้อมูลด้วยตนเอง การตอบกลับไม่เกี่ยวข้องกับการเรียกใช้ JSON.stringify () อย่างชัดเจนบนเซิร์ฟเวอร์ Node และไม่มีการเรียกใช้ JSON.parse () บนไคลเอ็นต์อย่างชัดเจน ที่จัดการทั้งหมดสำหรับคุณ

การใช้ "eval" เกี่ยวข้องกับความเสี่ยงด้านความปลอดภัยในการแทรกโค้ด คุณอาจคิดว่าไม่มีทางเกิดขึ้นได้ แต่แฮกเกอร์สามารถสร้างสรรค์ได้ นอกจากนี้ "eval" ยังเป็นปัญหาสำหรับการเพิ่มประสิทธิภาพของ Javascript

หากคุณพบว่าตัวเองใช้ฟังก์ชัน "stringify ()" โปรดทราบว่าบางฟังก์ชันที่มีชื่อนั้นจะสร้างสตริงที่เข้ากันได้กับ "eval" ไม่ใช่กับ JSON ตัวอย่างเช่นใน Node สิ่งต่อไปนี้จะให้ฟังก์ชันที่สร้างสตริงในรูปแบบที่เข้ากันได้กับ "eval":

var stringify = require('node-stringify'); // generates eval() format

สิ่งนี้มีประโยชน์ แต่ถ้าคุณไม่มีความต้องการเฉพาะก็อาจไม่ใช่สิ่งที่คุณต้องการ


1

หากการส่งคืนอาร์เรย์ใช้งานได้และส่งคืนอ็อบเจ็กต์เดียวคุณอาจลองส่งคืนอ็อบเจ็กต์เดี่ยวของคุณเป็นอาร์เรย์ที่มีอ็อบเจ็กต์เดี่ยวนั้น:

[ { title: "One", key: "1" } ]

ด้วยวิธีนี้คุณจะส่งคืนโครงสร้างข้อมูลที่สอดคล้องกันอาร์เรย์ของออบเจ็กต์ไม่ว่าจะเป็นส่วนข้อมูลก็ตาม

ฉันเห็นว่าคุณได้ลองใส่ออบเจ็กต์เดี่ยวของคุณใน "วงเล็บ" แล้วและแนะนำสิ่งนี้ด้วยตัวอย่างเนื่องจาก JavaScript ถือว่า [.. ] ต่างจาก (.. )


1

หากมีการเรียกตัวจัดการข้อผิดพลาดของ jQuery และอ็อบเจ็กต์ XHR มี "parser error" นั่นอาจเป็นข้อผิดพลาดของตัวแยกวิเคราะห์ที่กลับมาจากเซิร์ฟเวอร์

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

คุณส่งคืนสิ่งนี้จากแบ็กเอนด์ใด

ตัวอย่างเช่นในบริการ ASMX ซึ่งมักจะเป็นกรณีที่กำหนดพารามิเตอร์ให้กับ jQuery เป็นออบเจ็กต์ JSON แทนที่จะเป็นสตริง JSON หากคุณให้ jQuery เป็นออบเจ็กต์ JSON จริงสำหรับพารามิเตอร์ "data" มันจะทำให้เป็นอนุกรมเป็นคู่ k มาตรฐานและคั่นด้วย v แทนที่จะส่งเป็น JSON


1

ฉันพบในการใช้งานบางอย่างที่ฉันต้องเพิ่ม:

obj = new Object; obj = (data.obj);

ซึ่งดูเหมือนจะแก้ปัญหาได้ Eval หรือไม่ดูเหมือนว่าจะทำเหมือนกันทุกประการสำหรับฉัน


ใช้อ็อบเจกต์ลิเทอรัลเมื่อเริ่มต้นอ็อบเจ็กต์ใหม่ไม่ใช่อ็อบเจ็กต์คอนสตรัคเตอร์: var obj = {};
Andreas Grech

ใช่ฉันเห็น var myArray = [] สำหรับอาร์เรย์และ var myObject = {} ขอบคุณสำหรับเคล็ดลับ Dreas
Jay

1

jQuery เลือกคีย์ JSON บางคีย์ ฉันกำลังส่งข้อมูลโค้ด JSON นี้ใน PHP:

echo json_encode((object) array('result' => 'success'));

การเปลี่ยนชื่อคีย์ 'ผลลัพธ์' เป็นอย่างอื่นใช้งานได้ ฉันเดาว่านี่เป็นการชนกันของคำสงวนและอาจเป็นข้อผิดพลาดใน jQuery (1.4.2)


1

ในสภาพแวดล้อม ColdFusion สิ่งหนึ่งที่จะทำให้เกิดข้อผิดพลาดแม้จะมี JSON ที่มีรูปแบบดีก็คือการเปิดใช้งาน Enable Request Debugging Outputใน ColdFusion Administrator (ภายใต้การแก้จุดบกพร่องและการบันทึก> การตั้งค่าเอาต์พุตการดีบัก) ข้อมูลการดีบักจะถูกส่งคืนพร้อมกับข้อมูล JSON และจะทำให้ข้อมูลนั้นไม่ถูกต้อง


1

ลองดูด้วย

$.ajax({
    url: url,
    data:datas,
    success:function(datas, textStatus, jqXHR){
    var returnedData = jQuery.parseJSON(datas.substr(datas.indexOf('{')));
})};

ในกรณีเซิร์ฟเวอร์ของฉันตอบสนองด้วยอักขระที่ไม่รู้ก่อน "{"


1

ฉันได้รับ status = parseerror และ xhr.status = 200

ปัญหาสำหรับฉันคือ URL ที่อยู่ในการตอบกลับ JSON ที่ '\' เปลี่ยนเป็น '/' ได้แก้ไขสิ่งนี้แล้ว


0

ฉันกำลังดิ้นรนกับสิ่งนี้และใช้เวลาสองสามชั่วโมงในการพยายามหาสิ่งนี้จนกระทั่งฉันใช้ firebug เพื่อแสดงวัตถุข้อมูล

var data = eval("(" + data.responseText + ")");
console.log(data.count);

-1

ใช้

$data = yourarray(); 
json_encode($data)

ทางฝั่งเซิร์ฟเวอร์ ในฝั่งไคลเอ็นต์ใช้ ajax กับ Datatype JSON และตรวจสอบให้แน่ใจว่าการเข้ารหัสเอกสารของคุณไม่ใช่ UTF-8 ด้วย BOM ต้องเป็น UTF-8

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