jQuery sẽ không phân tích cú pháp JSON của tôi từ truy vấn AJAX


88

Tôi đang gặp khó khăn khi phân tích cú pháp một số dữ liệu JSON được trả về từ máy chủ của mình bằng jQuery.ajax ()

Để thực hiện AJAX tôi đang sử dụng:

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

Và nếu tôi trả về một mảng các mục thì nó hoạt động tốt:

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

Hàm thành công được gọi và nhận đúng đối tượng.

Tuy nhiên, khi tôi đang cố gắng trả về một đối tượng:

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

Hàm lỗi được gọi và xhr chứa 'lỗi phân tích cú pháp'. Tôi đã thử gói JSON trong dấu ngoặc đơn trên máy chủ trước khi gửi nó xuống dây, nhưng nó không có gì khác biệt. Tuy nhiên, nếu tôi dán nội dung vào một chuỗi trong Javascript và sau đó sử dụng hàm eval (), nó sẽ đánh giá nó một cách hoàn hảo.

Bất kỳ ý tưởng những gì tôi đang làm sai?

Anthony


Câu trả lời:


72

Máy chủ của bạn có đang gửi dữ liệu dưới dạng Content-Type "*/json"không? Nếu không, hãy sửa đổi tiêu đề phản hồi cho phù hợp. "application/json"Ví dụ, gửi sẽ tốt.


Lần phỏng đoán thứ hai này, đã gặp vấn đề tương tự một lần và thật ngạc nhiên rằng tôi đã sử dụng sai kiểu kịch câm. Nếu bạn đang thử nghiệm qua localhost trên windows, hãy lưu ý điều này. Hãy thử tải nó lên ở đâu đó và kiểm tra lại. Nếu bạn muốn nó hoạt động trên localhost, bạn phải thực sự đáp ứng yêu cầu.
Josh

51

Theo đặc điểm kỹ thuật của json.org , trả lại của bạn không hợp lệ. Tên luôn được trích dẫn, vì vậy bạn nên quay lại

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

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

Đây có thể không phải là vấn đề với thiết lập của bạn, vì bạn nói rằng một trong số chúng hoạt động ngay bây giờ, nhưng nó sẽ được sửa cho chính xác trong trường hợp bạn cần chuyển sang trình phân tích cú pháp JSON khác trong tương lai.


2
Thật vậy, trong jQuery 1.4 (ví dụ) { key: 'val' }không phải là JSON hợp lệ.
rfunduk

34

Chuỗi JSON được bọc trong đôi dấu ngoặc kép; dấu ngoặc kép không phải là một thay thế hợp lệ.

{"who": "Hello World"}

là hợp lệ nhưng điều này không ...

{'who': 'Hello World'}

Mặc dù không phải là vấn đề của OP, nhưng những người khác đã hạ cánh ở đây nghĩ rằng nó đáng chú ý.


30

Sự cố này thường là do yêu cầu của bạn nhận được không đúng loại kịch câm. Khi phát triển trên máy tính của riêng bạn, đôi khi bạn không nhận được loại kịch câm thích hợp từ "máy chủ", đó là máy tính của chính bạn. Tôi đã gặp sự cố này một lần khi phát triển bằng cách mở tệp được lưu trữ cục bộ trong trình duyệt (ví dụ: url là "c: /project/test.html").

Hãy thử sử dụng thuộc tính beforeSend để thêm một hàm gọi lại ghi đè kiểu mime. Điều này sẽ đánh lừa mã giao dịch với json mặc dù loại kịch câm sai được máy chủ gửi và nhận mã gọi điện của bạn. Dưới đây là một số mã ví dụ.

Loại kịch câm thích hợp là ứng dụng / json theo câu hỏi này , nhưng tôi biết rằng ứng dụng / j-son đã hoạt động khi tôi thử nó (bây giờ vài năm trước). Bạn có thể nên thử ứng dụng / json trước.

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...
 }
});

chỉ muốn nói rằng gợi ý beforeSend mà bạn đề xuất đã phù hợp với tôi !! cuộc gọi ajax của tôi hoạt động tốt trong safari và chrome nhưng không phải firefox. ngay sau khi tôi thêm beforeSend thì Firefox đã hoạt động ngay. ồ !! Cảm ơn!!
Karmen Blake

7

Tôi đã gặp sự cố này và tôi đã sử dụng một chút

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

để lấy dữ liệu trả về trong một đối tượng. nhưng sau đó gặp phải các vấn đề khác khi nhận được lỗi 'thiếu) trong dấu ngoặc đơn' và phát hiện ra rằng jQuery có một hàm đặc biệt để đánh giá một chuỗi cho cấu trúc json:

$.parseJSON(data)

nên làm thủ thuật. Tất nhiên, điều này là ngoài việc chuỗi json của bạn ở định dạng thích hợp ..


6

Nếu bạn đang lặp lại phản hồi json và tiêu đề của bạn không khớp với * / json thì bạn có thể sử dụng api jQuery.parseJSON tích hợp sẵn để phân tích cú pháp phản hồi.

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

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

Không phải như những gì bạn nghĩ. Dưới dạng một biểu thức, nó là một đối tượng theo nghĩa đen, nhưng như một câu lệnh, nó là:

{                // 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

Rất tiếc, eval () không cung cấp cho bạn cách xác định xem bạn đang đưa cho nó một câu lệnh hay một biểu thức và nó có xu hướng đoán sai.

Giải pháp thông thường thực sự là đặt bất kỳ thứ gì trong dấu ngoặc đơn trước khi gửi nó đến hàm eval (). Bạn nói rằng bạn đã thử điều đó trên máy chủ ... rõ ràng bằng cách nào đó điều đó không được thông qua. Sẽ không thấm nước khi nói ở phía máy khách, bất cứ điều gì đang nhận phản hồi XMLHttpRequest:

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

thay vì:

eval(responseText);

miễn là phản hồi thực sự là một biểu thức không phải là một tuyên bố. (ví dụ: nó không có nhiều mệnh đề được phân tách bằng dấu chấm phẩy hoặc dấu mới.)


Tôi nghĩ rằng jQuery tự động thêm dấu ngoặc đơn khi xử lý dữ liệu yêu cầu.
strager

2
Câu trả lời này rất hữu ích đối với tôi, vì tôi chưa bao giờ hiểu tại sao mọi người lại đặt JSON trong ngoặc đơn.
Andrey Tarantsov


2

Nếu bạn đang sử dụng Dịch vụ Web ASP.NET bằng jQuery, hãy đảm bảo rằng bạn có những thứ sau được bao gồm trong web.config của mình:

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

2

Tôi đã gặp sự cố tương tự với vấn đề này khi Firefox 3.5 hoạt động tốt và đã phân tích cú pháp dữ liệu JSON của tôi nhưng Firefox 3.0.6 trả về lỗi phân tích cú pháp. Hóa ra đó là một khoảng trống ở đầu JSON khiến Firefox 3.0.6 gặp lỗi. Xóa không gian trống đã sửa nó


2

Các kỹ thuật "eval ()" và "JSON.parse ()" sử dụng các định dạng loại trừ lẫn nhau.

  • Với dấu ngoặc đơn "eval ()" là bắt buộc .
  • Với dấu ngoặc "JSON.parse ()" bị cấm .

Hãy lưu ý, có các hàm "stringify ()" tạo ra định dạng "eval". Đối với ajax, bạn chỉ nên sử dụng định dạng JSON.

Trong khi "eval" kết hợp toàn bộ ngôn ngữ JavaScript, JSON chỉ sử dụng một tập hợp con nhỏ của ngôn ngữ. Trong số các cấu trúc trong ngôn ngữ JavaScript mà "eval" phải nhận ra là "Câu lệnh khối" (hay còn gọi là "câu lệnh ghép") ; là một cặp hoặc dấu ngoặc nhọn "{}" với một số câu lệnh bên trong. Nhưng dấu ngoặc nhọn cũng được sử dụng trong cú pháp của các đối tượng. Việc giải thích được phân biệt theo ngữ cảnh mà mã xuất hiện. Một cái gì đó có thể trông giống như một đối tượng theo nghĩa đen đối với bạn, nhưng "eval" sẽ xem nó như một câu lệnh ghép.

Trong ngôn ngữ JavaScript, các ký tự đối tượng xuất hiện ở bên phải của một phép gán.

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

Các ký tự đối tượng không tự xảy ra.

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

Quay trở lại câu hỏi ban đầu của OP, được hỏi vào năm 2008, anh ấy hỏi tại sao phần sau không thành công trong "eval ()":

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

Câu trả lời là nó trông giống như một câu lệnh ghép. Để chuyển đổi nó thành một đối tượng, bạn phải đặt nó vào ngữ cảnh mà câu lệnh ghép là không thể. Điều đó được thực hiện bằng cách đặt dấu ngoặc đơn xung quanh nó

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

OP cũng hỏi tại sao một tuyên bố tương tự lại đánh giá thành công:

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

Câu trả lời tương tự cũng áp dụng - dấu ngoặc nhọn nằm trong ngữ cảnh mà câu lệnh ghép là không thể. Đây là một ngữ cảnh mảng, " [...]" và các mảng có thể chứa các đối tượng, nhưng chúng không thể chứa các câu lệnh.

Không giống như "eval ()", JSON rất hạn chế về khả năng của nó. Hạn chế là cố ý. Người thiết kế JSON dự định một tập hợp con JavaScript tối giản, chỉ sử dụng cú pháp có thể xuất hiện ở phía bên phải của nhiệm vụ. Vì vậy, nếu bạn có một số mã phân tích cú pháp chính xác trong JSON ...

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

... điều đó ngụ ý rằng nó cũng sẽ phân tích cú pháp hợp pháp ở phía bên phải của một bài tập, như thế này ..

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

Nhưng đó không phải là hạn chế duy nhất đối với JSON. Đặc tả ngôn ngữ BNF cho JSON rất đơn giản. Ví dụ: nó không cho phép sử dụng các dấu ngoặc kép để biểu thị chuỗi (như JavaScript và Perl do) và nó không có cách nào để diễn đạt một ký tự dưới dạng byte (như 'C'). Thật không may, nó cũng không cho phép nhận xét (điều này thực sự tốt khi tạo tệp cấu hình). Mặt trái của tất cả những hạn chế đó là việc phân tích cú pháp JSON nhanh và không có cơ hội cho việc chèn mã (một mối đe dọa bảo mật).

Do những hạn chế này, JSON không được sử dụng cho dấu ngoặc đơn. Do đó, một dấu ngoặc trong chuỗi JSON là một ký tự không hợp lệ.

Luôn sử dụng định dạng JSON với ajax, vì những lý do sau:

  • Một đường ống ajax điển hình sẽ được định cấu hình cho JSON.
  • Việc sử dụng "eval ()" sẽ bị chỉ trích là một rủi ro bảo mật.

Ví dụ về đường ống ajax, hãy xem xét một chương trình liên quan đến máy chủ Node và máy khách jQuery. Chương trình khách sử dụng một cuộc gọi jQuery có dạng $.ajax({dataType:'json',...etc.});. JQuery tạo một đối tượng jqXHR để sử dụng sau này, sau đó đóng gói và gửi yêu cầu liên quan. Máy chủ chấp nhận yêu cầu, xử lý yêu cầu và sau đó sẵn sàng phản hồi. Chương trình máy chủ sẽ gọi phương thức res.json(data)để đóng gói và gửi phản hồi. Quay lại phía máy khách, jQuery chấp nhận phản hồi, tham vấn đối tượng jqXHR được liên kết và xử lý dữ liệu có định dạng JSON. Tất cả đều hoạt động mà không cần chuyển đổi dữ liệu thủ công. Phản hồi không liên quan đến lệnh gọi rõ ràng tới JSON.stringify () trên máy chủ Node và không có lệnh gọi rõ ràng nào đến JSON.parse () trên máy khách; đó là tất cả giải quyết cho bạn.

Việc sử dụng "eval" có liên quan đến rủi ro bảo mật khi đưa mã vào. Bạn có thể nghĩ rằng không có cách nào có thể xảy ra, nhưng các hacker có thể khá sáng tạo. Ngoài ra, "eval" là vấn đề đối với việc tối ưu hóa Javascript.

Nếu bạn thấy mình đang sử dụng một hàm "stringify ()", hãy lưu ý rằng một số hàm có tên đó sẽ tạo chuỗi tương thích với "eval" chứ không phải với JSON. Ví dụ: trong Node, phần sau cung cấp cho bạn hàm tạo chuỗi ở định dạng tương thích "eval":

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

Điều này có thể hữu ích, nhưng trừ khi bạn có nhu cầu cụ thể, nó có thể không phải là thứ bạn muốn.


1

Nếu trả về một mảng hoạt động và trả về một đối tượng thì không, bạn cũng có thể thử trả về đối tượng đơn lẻ của mình dưới dạng một mảng chứa đối tượng đơn lẻ đó:

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

theo cách đó, bạn đang trả về một cấu trúc dữ liệu nhất quán, một mảng các đối tượng, bất kể trọng tải dữ liệu.

tôi thấy rằng bạn đã thử gói đối tượng duy nhất của mình trong "ngoặc đơn" và đề xuất điều này với ví dụ vì tất nhiên JavaScript xử lý [..] khác với (..)


1

Nếu trình xử lý lỗi của jQuery đang được gọi và đối tượng XHR chứa "lỗi trình phân tích cú pháp", đó có thể là lỗi trình phân tích cú pháp quay lại từ máy chủ.

Có phải trường hợp nhiều kết quả của bạn khi bạn gọi dịch vụ mà không có tham số, nhưng nó bị phá vỡ khi bạn cố gắng cung cấp một tham số để truy xuất bản ghi duy nhất?

Bạn đang trả lại cái này từ chương trình phụ trợ nào?

Ví dụ: trên các dịch vụ ASMX, điều này thường xảy ra khi các tham số được cung cấp cho jQuery dưới dạng một đối tượng JSON thay vì một chuỗi JSON. Nếu bạn cung cấp cho jQuery một đối tượng JSON thực tế cho tham số "data" của nó, nó sẽ tuần tự hóa nó thành các cặp k, v tiêu chuẩn & được phân tách thay vì gửi nó dưới dạng JSON.


1

Tôi thấy trong một số triển khai của mình, tôi phải thêm:

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

mà dường như giải quyết được vấn đề. Đánh giá hay không nó dường như làm chính xác như nhau đối với tôi.


Sử dụng đối tượng theo nghĩa đen khi khởi tạo một đối tượng mới, không phải hàm tạo Đối tượng: var obj = {};
Andreas Grech

Vâng, tôi hiểu rồi, var myArray = [] cho mảng và var myObject = {}, cảm ơn vì mẹo Dreas
Jay

1

jQuery mắc kẹt trên các khóa JSON nhất định. Tôi đã gửi đoạn mã JSON này bằng PHP:

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

Đổi tên khóa 'kết quả' thành một thứ khác hoạt động. Tôi đoán đây là một sự va chạm từ dành riêng của một số loại, và có thể là một lỗi trong jQuery (1.4.2).


1

Trong môi trường ColdFusion, một điều sẽ gây ra lỗi, ngay cả với JSON đã được định dạng tốt, là đã bật Yêu cầu đầu ra gỡ lỗi trong Quản trị viên ColdFusion (trong Gỡ lỗi & ghi nhật ký> Cài đặt đầu ra gỡ lỗi). Thông tin gỡ lỗi sẽ được trả về cùng với dữ liệu JSON và do đó sẽ làm cho nó không hợp lệ.


1

cũng thử cái này

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

trong trường hợp máy chủ của tôi phản hồi bằng ký tự không xác định trước '{'


1

Tôi nhận được status = parseerror và xhr.status = 200.

Vấn đề đối với tôi là URL bên trong phản hồi JSON có '\' chuyển thành '/' đã sửa lỗi này.


0

Tôi đã đấu tranh với điều này và dành vài giờ để tìm ra điều này, cho đến khi tôi sử dụng firebug để hiển thị đối tượng dữ liệu.

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

-1

sử dụng

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

ở phía máy chủ. Về phía máy khách, hãy sử dụng ajax với Datatype JSON và đảm bảo mã hóa tài liệu của bạn không phải là UTF-8 với BOM mà phải là UTF-8.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.