HTML / Javascript: cách truy cập dữ liệu JSON được tải trong thẻ script với bộ src


90

Tôi có tệp JSON này mà tôi tạo trong máy chủ mà tôi muốn làm cho máy khách có thể truy cập được vì trang có thể xem được. Về cơ bản những gì tôi muốn đạt được là:

Tôi có thẻ sau được khai báo trong tài liệu html của mình:

<script id="test" type="application/json" src="http://myresources/stuf.json">

Tệp được giới thiệu trong nguồn của nó có dữ liệu JSON. Như tôi đã thấy, dữ liệu đã được tải xuống, giống như nó xảy ra với các tập lệnh.

Bây giờ, làm cách nào để truy cập nó trong Javascript? Tôi đã thử truy cập thẻ script, có và không có jQuery, sử dụng vô số phương pháp để cố gắng lấy dữ liệu JSON của mình, nhưng bằng cách nào đó điều này không hoạt động. Bắt nó innerHTMLsẽ hoạt động nếu dữ liệu json được viết nội tuyến trong tập lệnh. Đó không phải là điều mà tôi đang cố gắng đạt được.

Yêu cầu JSON từ xa sau khi tải trang cũng không phải là một tùy chọn, trong trường hợp bạn muốn đề xuất điều đó.


3
Thay vì tệp json, hãy đặt nó thành tệp javascript để gán đối tượng cho một biến. Cách tiếp cận khác là sử dụng ajax.
Asad Saeeduddin

3
Gợi ý đầu tiên là việc thực hiện hiện tại. Tôi không muốn làm điều đó vì tôi đang sử dụng hành vi để phân phối cấu trúc. Tôi muốn sử dụng cấu trúc cho cấu trúc (nếu tôi muốn JSON, tôi sẽ lấy JSON). Đề xuất thứ hai không được mong muốn (tôi cần dữ liệu này cho quá trình khởi tạo).
ChuckE

1
@ChuckE thông qua <script>thẻ hoặc thông qua AJAX, bạn vẫn sẽ phải đợi một yêu cầu HTTP bổ sung hoàn tất. Trình duyệt sẽ không cho phép bạn đọc nội dung tập lệnh nếu bạn tìm nạp nó bằng thuộc tính "src", vì vậy giải pháp thay thế duy nhất của bạn là thực hiện một yêu cầu AJAX.
Pointy

3
@Pointy thông qua thẻ <script> nội dung sẽ được đánh giá ngay sau khi được tải xuống. Nếu tôi đặt tập lệnh json của mình trước tập lệnh js của mình, dữ liệu tập lệnh json sẽ được đánh giá trước dữ liệu tập lệnh js, điều đó có nghĩa là, tôi sẽ không đợi, dữ liệu đã có ở đó. Về việc nó là giải pháp thay thế duy nhất của tôi, tôi muốn xem một số tài liệu chính thức trước khi đồng ý với bạn (không nói rằng bạn sai, chỉ đó chính xác là lý do tôi viết câu hỏi).
ChuckE

2
"Yêu cầu JSON từ xa sau khi tải trang cũng không phải là một tùy chọn, trong trường hợp bạn muốn đề xuất điều đó." ... yêu cầu JSON khác nhiều như thế nào so với yêu cầu được gửi bởi a <script src=""></script>? Cả hai đều sẽ thực hiện lệnh gọi GET chống lại máy chủ của bạn.
Ben Lesh

Câu trả lời:


114

Bạn không thể tải JSON như vậy, xin lỗi.

Tôi biết bạn đang nghĩ "tại sao tôi không thể sử dụng srcở đây? Tôi đã thấy những thứ như thế này ...":

<script id="myJson" type="application/json">
 { 
   name: 'Foo' 
 }
</script>

<script type="text/javascript">
    $(function() {
        var x = JSON.parse($('#myJson').html());
        alert(x.name); //Foo
     });
</script>

... hay nói một cách đơn giản, đó chỉ là thẻ script bị "lạm dụng" như một người giữ dữ liệu. Bạn có thể làm điều đó với tất cả các loại dữ liệu. Ví dụ: rất nhiều công cụ tạo mẫu tận dụng các thẻ script để giữ các mẫu .

Bạn có một danh sách ngắn các tùy chọn để tải JSON của mình từ một tệp từ xa:

  1. Sử dụng $.get('your.json')hoặc một số phương pháp AJAX khác.
  2. Viết một tệp đặt một biến toàn cục cho json của bạn. (có vẻ hokey).
  3. Kéo nó vào một iframe vô hình, sau đó quét nội dung của nó sau khi nó được tải (tôi gọi đây là "chế độ 1997")
  4. Tham khảo ý kiến ​​của một thầy tu voodoo.

Điểm cuối cùng:

Yêu cầu JSON từ xa sau khi tải trang cũng không phải là một tùy chọn, trong trường hợp bạn muốn đề xuất điều đó.

... điều đó không có ý nghĩa. Sự khác biệt giữa một yêu cầu AJAX và một yêu cầu được gửi bởi trình duyệt trong khi xử lý của bạn <script src="">về cơ bản là không có gì. Cả hai đều sẽ thực hiện GET trên tài nguyên. HTTP không quan tâm nếu nó được thực hiện vì thẻ script hay lệnh gọi AJAX và máy chủ của bạn cũng vậy.


5
Câu trả lời chính xác. Khi bạn nói "thẻ script bị 'lạm dụng'", bạn có nghĩa là đó là một cách sử dụng sai (có thể không sai, nhưng là "sáng tạo") của thẻ script? N của bạn. 2 là lựa chọn mà chúng tôi đã có trong quá trình sản xuất, tôi đang tìm kiếm một giải pháp json / no-js nghiêm ngặt, ngoài thử nghiệm thuần túy (tôi ổn với điều đó là không thể nếu tôi chắc chắn là vậy). Về điểm cuối cùng, tôi cần thông tin này trước sự kiện onload và tôi không muốn làm cho toàn bộ quá trình khởi tạo phụ thuộc vào một yêu cầu không đồng bộ có thể thay đổi về thời gian hoàn thành. Đây là điểm khác biệt chính giữa lệnh gọi Ajax và thẻ script.
ChuckE

1
Không, tôi không nghĩ nó "sai", nói chung, chỉ ... "sáng tạo" có lẽ là một từ tốt cho nó. Nếu thực sự có thể viết JSON vào <script>thẻ, tôi đoán là tôi sẽ đi theo con đường đó.
Ben Lesh

yeh, toàn bộ thách thức là tải nó bằng cách sử dụng thuộc tính src của thẻ script và "làm xáo trộn" thông tin này trong tài liệu.
ChuckE

Chà, bạn thực sự không thể ẩn dữ liệu khỏi người dùng trong ứng dụng trình duyệt phía máy khách. Họ chỉ có thể truy cập vào các công cụ dành cho nhà phát triển của trình duyệt của họ và thiết lập một điểm ngắt trong JavaScript và kiểm tra các đối tượng theo cách họ muốn.
Ben Lesh

1
@Jaydipsinh, sau đó bạn cần giải quyết các vấn đề CORS của mình và sử dụng Ajax. Có một lý do khiến trình duyệt không cho phép loại hành vi này. Hầu hết các trình duyệt thậm chí sẽ không cho phép bạn xâm nhập CORS bằng iframe nữa.
Ben Lesh 23/09/13

14

Một giải pháp khác là sử dụng ngôn ngữ kịch bản phía máy chủ và chỉ cần đưa vào nội tuyến dữ liệu json. Đây là một ví dụ sử dụng PHP:

<script id="data" type="application/json"><?php include('stuff.json'); ?></script>
<script>
var jsonData = JSON.parse(document.getElementById('data').textContent)
</script>

Ví dụ trên sử dụng một thẻ script bổ sung với type application/json. Một giải pháp đơn giản hơn nữa là đưa JSON trực tiếp vào JavaScript:

<script>var jsonData = <?php include('stuff.json');?>;</script>

Ưu điểm của giải pháp với thẻ phụ là mã JavaScript và dữ liệu JSON được giữ tách biệt với nhau.


+ đối với nội dung văn bản. .html không làm việc cho tôi trên thẻ script
Seth McClaine

9

Có vẻ như điều này là không thể, hoặc ít nhất là không được hỗ trợ.

Từ đặc tả HTML5 :

Khi được sử dụng để bao gồm các khối dữ liệu (trái ngược với tập lệnh), dữ liệu phải được nhúng nội tuyến , định dạng của dữ liệu phải được cung cấp bằng thuộc tính type, thuộc tính src không được chỉ định và nội dung của phần tử tập lệnh phải phù hợp các yêu cầu được xác định cho định dạng được sử dụng.


1
Có vẻ đây là một chính sách xử lý dữ liệu nhạy cảm hơn JS và CSS.

5

Mặc dù hiện tại không thể thực hiện được với scriptthẻ, nhưng có thể xảy ra với thẻ nếu thẻ iframetừ cùng một miền.

<iframe
id="mySpecialId"
src="/my/link/to/some.json"
onload="(()=>{if(!window.jsonData){window.jsonData={}}try{window.jsonData[this.id]=JSON.parse(this.contentWindow.document.body.textContent.trim())}catch(e){console.warn(e)}this.remove();})();"
onerror="((err)=>console.warn(err))();"
style="display: none;"
></iframe>

Để sử dụng ở trên, chỉ cần thay thế thuộc tính idsrcbằng những gì bạn cần. Các id(mà chúng tôi sẽ giả trong tình huống này là bằng mySpecialId) sẽ được sử dụng để lưu trữ các dữ liệu trong window.jsonData["mySpecialId"].

Nói cách khác, đối với mọi iframe có idvà sử dụng onloadtập lệnh sẽ có dữ liệu đó được tải đồng bộ vào window.jsonDatađối tượng theo idchỉ định.

Tôi đã làm điều này cho vui và để chứng tỏ rằng nó "có thể" nhưng tôi không khuyên bạn nên sử dụng nó.


Đây là một giải pháp thay thế sử dụng một cuộc gọi lại.

<script>
    function someCallback(data){
        /** do something with data */
        console.log(data);

    }
    function jsonOnLoad(callback){
        const raw = this.contentWindow.document.body.textContent.trim();
        try {
          const data = JSON.parse(raw);
          /** do something with data */
          callback(data);
        }catch(e){
          console.warn(e.message);
        }
        this.remove();
    }
</script>
<!-- I frame with src pointing to json file on server, onload we apply "this" to have the iframe context, display none as we don't want to show the iframe -->
<iframe src="your/link/to/some.json" onload="jsonOnLoad.apply(this, someCallback)" style="display: none;"></iframe>

Đã thử nghiệm trong chrome và sẽ hoạt động trong firefox. Không chắc chắn về IE hoặc Safari.


3

Tôi đồng ý với Ben. Bạn không thể tải / nhập tệp JSON đơn giản.

Nhưng nếu bạn hoàn toàn muốn làm điều đó và có thể linh hoạt cập nhật tệp json, bạn có thể

my-json.js

   var myJSON = {
      id: "12ws",
      name: "smith"
    }

index.html

<head>
  <script src="my-json.js"></script>
</head>
<body onload="document.getElementById('json-holder').innerHTML = JSON.stringify(myJSON);">
  <div id="json-holder"></div>
</body>

2

Kiểm tra câu trả lời sau: https://stackoverflow.com/a/7346598/1764509

$.getJSON("test.json", function(json) {
    console.log(json); // this will show the info it in firebug console
});

3
$ .getJSON () là một lệnh gọi ajax.
Tobi G.

Làm cách nào để hiển thị thông tin trong tệp HTML được liên kết thay vì bảng điều khiển?
T.Doe

2

Nếu bạn cần tải JSON từ một miền khác: http://en.wikipedia.org/wiki/JSONP
Tuy nhiên, hãy lưu ý các cuộc tấn công XSSI tiềm ẩn: https://www.scip.ch/vi/?labs.20160414

Nếu đó là cùng một miền thì chỉ cần sử dụng Ajax.


2
JSONP không hoạt động với các kết quả có định dạng JSON. Ngoài ra, các tham số JSONP được truyền dưới dạng đối số cho một tập lệnh được xác định bởi máy chủ… mà bạn có thể không có quyền truy cập.
e-sushi

1

đặt một cái gì đó như thế này trong tệp kịch bản của bạn json-content.js

var mainjson = { your json data}

sau đó gọi nó từ thẻ script

<script src="json-content.js"></script>

thì bạn có thể sử dụng nó trong tập lệnh tiếp theo

<script>
console.log(mainjson)
</script>

0

Một thay thế khác để sử dụng json chính xác trong javascript. Vì nó là Ký hiệu đối tượng Javascript, bạn chỉ có thể tạo đối tượng của mình trực tiếp bằng ký hiệu json. Nếu bạn lưu trữ tệp này trong tệp .js, bạn có thể sử dụng đối tượng này trong ứng dụng của mình. Đây là một tùy chọn hữu ích cho tôi khi tôi có một số dữ liệu json tĩnh mà tôi muốn lưu vào bộ nhớ cache trong một tệp riêng biệt với phần còn lại của ứng dụng của mình.

    //Just hard code json directly within JS
    //here I create an object CLC that represents the json!
    $scope.CLC = {
        "ContentLayouts": [
            {
                "ContentLayoutID": 1,
                "ContentLayoutTitle": "Right",
                "ContentLayoutImageUrl": "/Wasabi/Common/gfx/layout/right.png",
                "ContentLayoutIndex": 0,
                "IsDefault": true
            },
            {
                "ContentLayoutID": 2,
                "ContentLayoutTitle": "Bottom",
                "ContentLayoutImageUrl": "/Wasabi/Common/gfx/layout/bottom.png",
                "ContentLayoutIndex": 1,
                "IsDefault": false
            },
            {
                "ContentLayoutID": 3,
                "ContentLayoutTitle": "Top",
                "ContentLayoutImageUrl": "/Wasabi/Common/gfx/layout/top.png",
                "ContentLayoutIndex": 2,
                "IsDefault": false
            }
        ]
    };
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.