jQuery.parseJSON ném ra lỗi JSON JSON không hợp lệ do thoát trích dẫn đơn trong JSON


202

Tôi đang thực hiện các yêu cầu đến máy chủ của mình bằng cách sử dụng jQuery.post()và máy chủ của tôi đang trả về các đối tượng JSON (như { "var": "value", ... }). Tuy nhiên, nếu bất kỳ giá trị nào chứa một trích dẫn (được thoát đúng như thế \'), jQuery không thể phân tích cú pháp chuỗi JSON hợp lệ. Đây là một ví dụ về ý tôi muốn nói ( được thực hiện trong bảng điều khiển của Chrome ):

data = "{ \"status\": \"success\", \"newHtml\": \"Hello \\\'x\" }";
eval("x = " + data); // { newHtml: "Hello 'x", status: "success" }

$.parseJSON(data); // Invalid JSON: { "status": "success", "newHtml": "Hello \'x" }

Điều này có bình thường không? Có cách nào để chuyển đúng một trích dẫn qua JSON không?

Câu trả lời:


325

Theo sơ đồ máy trạng thái trên trang web JSON , chỉ cho phép thoát các ký tự trích dẫn kép, không được trích dẫn đơn. Các ký tự trích dẫn đơn không cần phải thoát:

http://www.json.org/opes.gif


Cập nhật - Thêm thông tin cho những người quan tâm:


Douglas Crockford không nói cụ thể tại sao đặc tả JSON không cho phép thoát các dấu ngoặc đơn trong chuỗi. Tuy nhiên, trong cuộc thảo luận về JSON trong Phụ lục E của JavaScript: Các bộ phận tốt , ông viết:

Các mục tiêu thiết kế của JSON là tối thiểu, di động, văn bản và một tập hợp con của JavaScript. Chúng ta càng ít đồng ý để tương tác, chúng ta càng dễ dàng tương tác.

Vì vậy, có lẽ ông quyết định chỉ cho phép các chuỗi được xác định bằng cách sử dụng dấu ngoặc kép vì đây là một quy tắc ít hơn mà tất cả các triển khai JSON phải đồng ý. Kết quả là, một ký tự trích dẫn trong một chuỗi vô tình chấm dứt chuỗi, bởi vì theo định nghĩa, một chuỗi chỉ có thể được chấm dứt bởi một ký tự trích dẫn kép. Do đó, không cần phải cho phép thoát một ký tự trích dẫn trong đặc tả chính thức.


Đào một chút sâu hơn, Crockford org.json thực hiện JSON cho Java là cho phép hơn và không cho phép ký tự dấu nháy đơn:

Các văn bản được tạo bởi các phương thức toString tuân thủ nghiêm ngặt các quy tắc cú pháp JSON. Các nhà xây dựng dễ tha thứ hơn trong các văn bản mà họ sẽ chấp nhận:

...

  • Chuỗi có thể được trích dẫn với '(trích dẫn đơn).

Điều này được xác nhận bởi mã nguồn JSONTokener . Các nextStringphương pháp chấp nhận thoát ký tự dấu nháy đơn và xử lý chúng giống như ký tự ngoặc kép:

public String nextString(char quote) throws JSONException {
    char c;
    StringBuffer sb = new StringBuffer();
    for (;;) {
        c = next();
        switch (c) {

        ...

        case '\\':
            c = this.next();
            switch (c) {

            ...

            case '"':
            case '\'':
            case '\\':
            case '/':
                sb.append(c);
                break;
        ...

Ở đầu phương thức là một nhận xét thông tin:

Định dạng JSON chính thức không cho phép các chuỗi trong dấu ngoặc đơn, nhưng việc triển khai được phép chấp nhận chúng.

Vì vậy, một số triển khai sẽ chấp nhận dấu ngoặc đơn - nhưng bạn không nên dựa vào điều này. Nhiều triển khai phổ biến khá hạn chế về vấn đề này và sẽ từ chối JSON có chứa các chuỗi trích dẫn đơn và / hoặc thoát các trích dẫn đơn.


Cuối cùng, để buộc câu hỏi này trở lại câu hỏi ban đầu, jQuery.parseJSONtrước tiên hãy thử sử dụng trình phân tích cú pháp JSON gốc của trình duyệt hoặc thư viện được tải như json2.js khi áp dụng (mà trên ghi chú bên cạnh là thư viện dựa trên logic của jQuery nếu JSONkhông được xác định) . Do đó, jQuery chỉ có thể được cho phép như triển khai cơ bản:

parseJSON: function( data ) {
    ...

    // Attempt to parse using the native JSON parser first
    if ( window.JSON && window.JSON.parse ) {
        return window.JSON.parse( data );
    }

    ...

    jQuery.error( "Invalid JSON: " + data );
},

Theo như tôi biết thì các triển khai này chỉ tuân thủ đặc tả JSON chính thức và không chấp nhận các trích dẫn đơn, do đó jQuery cũng không.


4
CẬP NHẬT :: JQuery rất hạn chế khi vượt qua JSON. Nếu bạn thử cảnh báo ($. ParseJSON ("[\" Ciao \\ '\ "]")); nó không hoạt động vì những gì Justin đã báo cáo
daitangio

2
" Việc triển khai JSON cho Java cho Java của Crockford được cho phép nhiều hơn và cho phép các ký tự trích dẫn đơn " # Đó chỉ là cách thực hành tốt: nguyên tắc mạnh mẽ
Duncan Jones

1
@DuncanJones - Bài viết này có thể cung cấp cái nhìn sâu sắc về lý do tại sao không có trình duyệt nào dường như tuân theo nguyên tắc đó liên quan đến JSON: joelonsoftware.com/items/2008/03/17.html
Justin Ethier

1
@JustinEthier như được chỉ ra bởi câu trả lời này stackoverflow.com/a/25491642/759452 , công cụ đặc tả JSON.ietf.org/html/rfc7159 nói Any character may be escaped, điều này có thể giải thích tại sao một số thực thi sẽ cho phép thoát các trích dẫn đơn lẻ.
Adrien Be

1
@AdrienBe - Thú vị ... nhưng họ có nghĩa là bất kỳ nhân vật nào cũng có thể thoát được nếu nó bao gồm 4 chữ số hex? Theo cả sơ đồ trạng thái ở trên và một trong phần 7 của RFC, việc thoát khỏi một trích dẫn như được viết \'vẫn không được phép. Sẽ thật tốt nếu RFC rõ ràng hơn về điểm này.
Justin Ethier

15

Nếu bạn cần một trích dẫn bên trong chuỗi, vì \ 'không được xác định bởi thông số kỹ thuật, hãy sử dụng \u0027 xem http://www.utf8-chartable.de/ cho tất cả các chuỗi

chỉnh sửa: xin vui lòng loại bỏ sự lạm dụng của tôi từ backticks trong các ý kiến. Tôi có nghĩa là dấu gạch chéo ngược. Quan điểm của tôi ở đây là trong trường hợp bạn có các chuỗi lồng nhau bên trong các chuỗi khác, tôi nghĩ rằng có thể hữu ích và dễ đọc hơn khi sử dụng unicode thay vì nhiều dấu gạch chéo ngược để thoát một trích dẫn. Nếu bạn không được lồng nhau tuy nhiên thực sự dễ dàng hơn chỉ cần đặt một trích dẫn cũ đơn giản vào đó.


29
Không. Chỉ cần sử dụng một trích dẫn đơn giản.
Jeff Kaufman

Đôi khi, nó đơn giản dễ sử dụng unicode hơn hàng tấn back-tick. Đặc biệt khi bên trong xen kẽ tick-tick.
slf

3
Tại sao bạn cần backticks? Nếu bạn có một chuỗi như "foo 'bar'" thì bạn chỉ cần để lại dấu ngoặc đơn.
Jeff Kaufman

3
Chính xác những gì tôi đang tìm kiếm. Tôi đang cố gắng viết một chuỗi json lên một trang dưới dạng một chuỗi js và đặt nó trong các dấu ngoặc đơn và nó bị chấm dứt sớm bất cứ khi nào một giá trị thuộc tính có một trích dẫn trong đó. Bây giờ tôi chỉ cần thực hiện một json.Replace ("'", "\ u0027") trong mã phía sau trước khi viết nó lên trang.
Zack

@Zack Bạn không nên kèm theo JSON với dấu ngoặc kép. Nếu bạn cần một chuỗi trong chuỗi JSON hiện có, chỉ cần xâu chuỗi lại. trong PHP, đó sẽ là var jsonEncodedAsString = <?= json_encode(myEncodedJson) ?>nơi myEncodedJsonlà kết quả của một trước json_encodeđó sẽ chăm sóc thoát quote đơn của bạn, trên thực tế, nó sẽ có dấu ngoặc kép chỉ ra một cái gì đó một chuỗi lớn được bọc trong dấu ngoặc kép, vì vậy dấu nháy đơn sẽ không được trốn thoát, nhưng đôi sẽ.
Juan Mendes

5

Tôi hiểu vấn đề nằm ở đâu và khi tôi nhìn vào thông số kỹ thuật thì rõ ràng rằng các trích dẫn đơn không được giải mã cần được phân tích chính xác.

Tôi đang sử dụng hàm jQuery.parseJSON của jquery để phân tích chuỗi JSON nhưng vẫn gặp lỗi phân tích cú pháp khi có một trích dẫn trong dữ liệu được chuẩn bị với json_encode.

Có thể đó là một lỗi trong quá trình triển khai của tôi giống như thế này (PHP - phía máy chủ):

$data = array();

$elem = array();
$elem['name'] = 'Erik';
$elem['position'] = 'PHP Programmer';
$data[] = json_encode($elem);

$elem = array();
$elem['name'] = 'Carl';
$elem['position'] = 'C Programmer';
$data[] = json_encode($elem);

$jsonString = "[" . implode(", ", $data) . "]";

Bước cuối cùng là tôi lưu trữ chuỗi được mã hóa JSON vào một biến JS:

<script type="text/javascript">
employees = jQuery.parseJSON('<?=$marker; ?>');
</script>

Nếu tôi sử dụng "" thay vì '', nó vẫn bị lỗi.

GIẢI PHÁP:

Điều duy nhất hiệu quả với tôi là sử dụng bitmask JSON_HEX_APOS để chuyển đổi các trích dẫn đơn như thế này:

json_encode($tmp, JSON_HEX_APOS);

Có cách nào khác để giải quyết vấn đề này? Là mã của tôi sai hoặc viết kém?

Cảm ơn


'<? = $ đánh dấu; ?> 'đây không phải là hợp lệ json. Các trích dẫn xung quanh bị "ăn" bởi trình thông dịch javascript, để lại một chuỗi bắt đầu bằng <... thứ bạn thực sự muốn thử là một trong số này: jQuery.parseJSON ('"<? = $ Marker;?>" '); jQuery.parseJSON ("\" <? = $ Marker;?> \ ""); Theo thông số kỹ thuật, chuỗi json phải sử dụng dấu ngoặc kép, nhưng javascript không quan tâm, vì vậy, bạn có một chuỗi javascript trích dẫn đơn hoặc trích dẫn kép, nhưng nếu bạn sử dụng chuỗi sau, bạn phải thoát tất cả sử dụng dấu ngoặc kép bên trong chuỗi.
Chris Cogdon

3

Khi bạn đang gửi một trích dẫn trong một truy vấn

empid = " T'via"
empid =escape(empid)

Khi bạn nhận được giá trị bao gồm một trích dẫn

var xxx  = request.QueryString("empid")
xxx= unscape(xxx)

Nếu bạn muốn tìm kiếm / chèn giá trị bao gồm một trích dẫn trong truy vấn xxx=Replace(empid,"'","''")


1
Nhưng không cần phải thoát một trích dẫn khi chuyển nó thành một phần của chuỗi JSON ...
Justin Ethier 15/03/13

2

Vấn đề tương tự khi sử dụng CakePHP để xuất ra một khối tập lệnh JavaScript bằng cách sử dụng nguồn gốc của PHP json_encode. $contractorCompanieschứa các giá trị có dấu ngoặc kép đơn và như được giải thích ở trên và dự kiến json_encode($contractorCompanies)sẽ không thoát khỏi chúng vì JSON hợp lệ của nó.

<?php $this->Html->scriptBlock("var contractorCompanies = jQuery.parseJSON( '".(json_encode($contractorCompanies)."' );"); ?>

Bằng cách thêm addlash () xung quanh chuỗi được mã hóa JSON, sau đó bạn thoát khỏi dấu ngoặc kép cho phép Cake / PHP lặp lại javascript chính xác cho trình duyệt. Lỗi JS biến mất.

<?php $this->Html->scriptBlock("var contractorCompanies = jQuery.parseJSON( '".addslashes(json_encode($contractorCompanies))."' );"); ?>

1

Tôi đã cố lưu một đối tượng JSON từ yêu cầu XHR vào thuộc tính dữ liệu HTML5 *. Tôi đã thử nhiều giải pháp trên mà không thành công.

Điều cuối cùng tôi làm là thay thế đoạn trích dẫn 'bằng mã &#39;bằng cách sử dụng biểu thức chính quy sau khi phương thức stringify () gọi theo cách sau:

var productToString = JSON.stringify(productObject);
var quoteReplaced = productToString.replace(/'/g, "&#39;");
var anchor = '<a data-product=\'' + quoteReplaced + '\' href=\'#\'>' + productObject.name + '</a>';
// Here you can use the "anchor" variable to update your DOM element.

0

Hấp dẫn. Làm thế nào bạn tạo JSON của bạn ở cuối máy chủ? Bạn có đang sử dụng chức năng thư viện (chẳng hạn nhưjson_encode trong PHP) hoặc bạn đang xây dựng chuỗi JSON bằng tay?

Điều duy nhất thu hút sự chú ý của tôi là dấu nháy thoát ( \'). Xem như bạn đang sử dụng dấu ngoặc kép, như bạn thực sự nên, không cần phải thoát dấu ngoặc đơn. Tôi không thể kiểm tra xem đó có thực sự là nguyên nhân gây ra lỗi jQuery của bạn không, vì bản thân tôi chưa cập nhật lên phiên bản 1.4.1.


Tôi sử dụng một thư viện trong PHP để tạo đối tượng JSON - hơi bị bỏ lỡ để viết nó xuống. Cảm ơn đã chỉ ra rằng.
Erik erpnjak
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.