HTML / Javascript: jak uzyskać dostęp do danych JSON załadowanych do tagu skryptu z ustawionym src


90

Mam ten plik JSON, który wygenerowałem na serwerze, który chcę udostępnić na kliencie, gdy strona jest widoczna. Zasadniczo chcę osiągnąć:

Mam następujący tag zadeklarowany w moim dokumencie HTML:

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

Plik, do którego odnosi się jego źródło, zawiera dane JSON. Jak widziałem, dane zostały pobrane, tak jak to się dzieje ze skryptami.

Jak mogę uzyskać do niego dostęp w JavaScript? Próbowałem uzyskać dostęp do tagu skryptu, z jQuery i bez niego, używając wielu metod, aby spróbować uzyskać moje dane JSON, ale jakoś to nie działa. Uzyskanie innerHTMLtego zadziałałoby, gdyby dane json zostały zapisane w skrypcie. Które nie było i nie jest tym, co próbuję osiągnąć.

Zdalne żądanie JSON po załadowaniu strony również nie jest opcją, jeśli chcesz to zasugerować.


3
Zamiast pliku json, uczyń go plikiem javascript, który przypisuje obiekt do zmiennej. Innym podejściem jest użycie Ajax.
Asad Saeeduddin

3
Pierwsza sugestia dotyczy aktualnej implementacji. Nie chciałbym tego robić, ponieważ używam zachowania do dostarczania struktury. Wolałbym użyć struktury dla struktury (jeśli chcę JSON, dostanę JSON). Druga sugestia nie jest potrzebna (potrzebuję tych danych do procesu inicjalizacji).
ChuckE

1
@ChuckE przez <script>tag lub przez AJAX, nadal będziesz musiał czekać na zakończenie dodatkowego żądania HTTP. Przeglądarka nie pozwoli ci odczytać zawartości skryptu, jeśli pobierzesz go z atrybutem „src”, więc jedyną alternatywą jest wysłanie żądania AJAX.
Pointy

3
@Pointy poprzez tag <script> zostanie sprawdzona zaraz po pobraniu. Jeśli umieszczę mój skrypt json przed skryptem js, dane skryptu json zostaną ocenione przed danymi skryptu js, co oznacza, że ​​nie będę czekać, dane już tam są. Jeśli chodzi o to, że jest to moja jedyna alternatywa, chciałbym zapoznać się z oficjalną dokumentacją, zanim się z tobą zgodzę (nie mówiąc, że się mylisz, tylko dlatego właśnie napisałem pytanie).
ChuckE

2
„Zdalne żądanie JSON po załadowaniu strony również nie jest opcją, jeśli chcesz to zasugerować”. ... czym żądanie JSON różni się tak bardzo od żądania wysłanego przez <script src=""></script>? Obaj będą wykonywać wywołania GET na Twoim serwerze.
Ben Lesh

Odpowiedzi:


114

Nie możesz tak załadować JSON, przepraszam.

Wiem, że myślisz "dlaczego nie mogę po prostu użyć srctutaj? Widziałem takie rzeczy ...":

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

… cóż, mówiąc prościej, był to tylko znacznik skryptu, który był „nadużywany” jako posiadacz danych. Możesz to zrobić z różnymi rodzajami danych. Na przykład wiele mechanizmów tworzenia szablonów wykorzystuje tagi skryptów do przechowywania szablonów .

Masz krótką listę opcji ładowania JSON ze zdalnego pliku:

  1. Użyj $.get('your.json')lub innej takiej metody AJAX.
  2. Napisz plik, który ustawia zmienną globalną na twój plik json. (wydaje się dziwny).
  3. Przeciągnij go do niewidocznego elementu iframe, a następnie zeskrob jego zawartość po załadowaniu (nazywam to „trybem 1997”)
  4. Skonsultuj się z kapłanem voodoo.

Punkt końcowy:

Zdalne żądanie JSON po załadowaniu strony również nie jest opcją, jeśli chcesz to zasugerować.

... to nie ma sensu. Różnica między żądaniem AJAX a żądaniem wysłanym przez przeglądarkę podczas przetwarzania Twojego <script src="">to w zasadzie nic. Oboje będą wykonywać GET na zasobie. HTTP nie dba o to, czy jest to zrobione z powodu tagu skryptu lub wywołania AJAX, podobnie jak twój serwer.


5
Świetna odpowiedź. Kiedy mówisz „nadużywany tag script”, masz na myśli niewłaściwe (może nie złe, ale „kreatywne”) użycie tagu script? Twój n. Opcja 2 to ta, którą już mamy w produkcji, szukałem rozwiązania ściśle json / no-js, z czystego eksperymentowania (nie przeszkadza mi to, jeśli jestem pewien, że jest). Jeśli chodzi o ostatni punkt, potrzebuję tych informacji przed zdarzeniem onload i nie chcę, aby cała inicjalizacja zależała od żądania asynchronicznego, które może różnić się w czasie zakończenia. To jest kluczowa różnica między wywołaniem Ajax a tagiem skryptu.
ChuckE

1
Nie, nie sądzę, żeby to było „złe”, powiedzmy, po prostu… „kreatywny” to prawdopodobnie dobre słowo na to. Jeśli faktycznie zapisanie JSON w <script>tagu jest możliwe, myślę, że wybrałbym tę trasę.
Ben Lesh

tak, całe wyzwanie polegało na ładowaniu go przy użyciu atrybutu src znacznika skryptu i „zaciemnianiu” tych informacji w dokumencie.
ChuckE

Cóż, tak naprawdę nie można ukryć danych przed użytkownikami w aplikacji przeglądarki po stronie klienta. Mogą po prostu wejść do narzędzi programistycznych przeglądarki i ustawić punkt przerwania w JavaScript i badać obiekty w dowolny sposób.
Ben Lesh

1
@Jaydipsinh, musisz rozwiązać problemy z CORS i użyć Ajax. Jest powód, dla którego przeglądarki nie zezwalają na tego typu zachowanie. Większość przeglądarek nie pozwala już nawet hakować CORS-a za pomocą elementu iframe.
Ben Lesh,

14

Innym rozwiązaniem byłoby wykorzystanie języka skryptowego po stronie serwera i po prostu dołączenie wbudowanej biblioteki json-data. Oto przykład wykorzystujący PHP:

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

Powyższy przykład używa dodatkowego tagu skryptu z typem application/json. Jeszcze prostszym rozwiązaniem jest dołączenie JSON bezpośrednio do JavaScript:

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

Zaletą rozwiązania z dodatkowym tagiem jest to, że kod JavaScript i dane JSON są oddzielone od siebie.


+ dla treści tekstowych. .html nie działa dla mnie w tagu skryptu
Seth McClaine

9

Wygląda na to, że nie jest to możliwe lub przynajmniej nie jest obsługiwane.

Ze specyfikacji HTML5 :

Gdy jest używany do dołączania bloków danych (w przeciwieństwie do skryptów), dane muszą być osadzone w tekście , format danych należy podać za pomocą atrybutu type, atrybut src nie może być określony , a zawartość elementu skryptu musi być zgodna do wymagań określonych dla używanego formatu.


1
Wydaje się, że należy traktować dane jako bardziej wrażliwe niż JS i CSS.

5

Chociaż obecnie nie jest to możliwe w przypadku scripttagu, jest to możliwe w iframeprzypadku tagu z tej samej domeny.

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

Aby skorzystać z powyższym, po prostu zastąpić idi srcatrybut z tym, co trzeba. id(Które będziemy zakładać w tej sytuacji jest równa mySpecialId) będzie używany do przechowywania danych w window.jsonData["mySpecialId"].

Innymi słowy, dla każdego elementu iframe, który ma skrypt idi używa onloadskryptu, dane te będą synchronicznie ładowane do window.jsonDataobiektu pod idokreślonym.

Zrobiłem to dla przyjemności i żeby pokazać, że jest to „możliwe”, ale nie polecam tego używać.


Oto alternatywa, która zamiast tego używa wywołania zwrotnego.

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

Przetestowany w chromie i powinien działać w przeglądarce Firefox. Nie mam pewności co do przeglądarki IE lub Safari.


3

Zgadzam się z Benem. Nie można załadować / zaimportować prostego pliku JSON.

Ale jeśli absolutnie chcesz to zrobić i masz elastyczność w aktualizowaniu pliku json, możesz

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>



1

umieść coś takiego w swoim pliku skryptu json-content.js

var mainjson = { your json data}

następnie wywołaj go z tagu script

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

następnie możesz go użyć w następnym skrypcie

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

0

Inna alternatywa dla użycia dokładnego json w javascript. Ponieważ jest to notacja obiektowa JavaScript, możesz po prostu utworzyć obiekt bezpośrednio z notacją JSON. Jeśli przechowujesz to w pliku .js, możesz użyć tego obiektu w swojej aplikacji. Była to przydatna opcja, gdy miałem statyczne dane json, które chciałem przechowywać w pliku oddzielnie od reszty mojej aplikacji.

    //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
            }
        ]
    };
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.