Tobias Fritsch: Per Javascript feststellen, ob eine Datei existiert - ist das möglich?

Die Frage ist mir etwas peinlich, aber ich bin mit meinem - zugegebenermaßen sehr kleinen - Latein am Ende.

Problemstellung: Ich möchte eine Verlinkung nur einblenden, wenn eine Datei auf dem Server vorhanden ist. Da diese Sache auf einem Authoring-Tool für Lernanwendungen aufsitzt, kann ich nur Javascript verwenden und (zumindest vermute ich das sehr stark) nicht ohne weiteres weitere Bibliotheken aufsetzen. Um die Dinge beim Namen zu nennen: Es geht um Captivate und die Frage, ob die Datei "a10.pdf" vorhanden ist.

Hier mein letzter Versuch:

var request = new XMLHttpRequest();
request.open('POST','a10.pdf', true);
if (request.status >= 200 && request.status < 300) {
cp.show("a10_but");
         alert('a10.pdf vorhanden');
      } else {
cp.hide("a10_but");
         alert('a10.pdf NICHTvorhanden');
      }; 

Die Zeilen

cp.show("a10_but");
alert('a10.pdf vorhanden');

und

cp.hide("a10_but");
alert('a10.pdf NICHTvorhanden');

funktionieren. Es wird ein in Captivate angelegtes Element - "a10but" - angezeigt oder eben nicht. Das Element enthält die komplette Verlinkung. Ich habe das durch eine andere Abfrage, als meinem Versuch das Vorhandensein einer Datei abzufragen, ausprobiert. Der alert kommt später wieder raus.

Der Wurm ist also im Teil:

var request = new XMLHttpRequest();
request.open('POST','a10.pdf', true);
if (request.status >= 200 && request.status < 300)

denn die Meldung ist jedes mal, egal ob die Datei vorhanden ist oder nicht, "a10.pdf NICHTvorhanden".

Folgende Varianten habe ich u.a. bereits ebenfalls ohne Erfolg probiert:

  • kompletter absoluter URL statt "a10.pdf"
  • "HEAD" statt "POST"
  • Einbettung in einen Eventhandler (den ich aber eigentlich sowieso unbedingt vermeiden möchte, weil es im Gesamtprojekt nicht um eine, sondern mehrere Dutzend Dateien geht)
  • Die Variante mit der Abfrage, ob ein "Bild" vorhanden ist:

var tmp=new Image;
    tmp.src='http://xyz.de/test/a10.pdf';
    if(tmp.complete)       
        alert("Datei vorhanden");       
    else       
    alert("Datei nicht vorhanden");

Ich habe bisher immer nur soweit gescripted (meistens eben etwas angepasst), wie ich es gebraucht habe und es ist mir bewusst, dass mir im Grunde auch die Basics fehlen, was ich sukzessive nachholen möchte. Entsprechende Hinweise helfen mir aber alleine nicht weiter. ;) Wohl aber Aussagen, wo ich hier den offensichtlich ja vorhandenen Bock geschossen habe - oder eben auch, dass sowas allein mit Javascript ohne den Umweg über eine PHP-Datei (den ich ja nicht gehen kann) einfach nicht machbar ist.

akzeptierte Antworten

  1. Ohne jetzt ins Detail zu steigen, denke ich, dasss diese Zeile

    request.open('POST','a10.pdf', true);
    

    nicht funktionieren kann. Wo soll a10.pdf denn gesucht werden? Wenn ich Dateien lese, fängt eine Web- Adresse immer mit http:// an.

    Und dann gibt es bei Javascript zusätzlich einen Hemmschuh, die Same-Origin-Policy.

    Linuchs

    1. Ohne jetzt ins Detail zu steigen, denke ich, dasss diese Zeile

      request.open('POST','a10.pdf', true);
      

      nicht funktionieren kann. Wo soll a10.pdf denn gesucht werden? Wenn ich Dateien lese, fängt eine Web- Adresse immer mit http:// an.

      Und dann gibt es bei Javascript zusätzlich einen Hemmschuh, die Same-Origin-Policy.

      Linuchs

      Danke für den Hinweis, das allein war jedoch nicht das Problem, hattee es wie gesagt auch mit http://www.xyz.de/test/a10.pdf ausprobiert.

      Folgende Varianten habe ich u.a. bereits ebenfalls ohne Erfolg probiert: [...] kompletter absoluter URL statt "a10.pdf"

      Das Skripting zur Abfrage lag ebenfalls auf diesem Server. Trotzdem wie gesagt vielen Dank, ich bin für alles dankbar, was weiterhelfen könnte! :)

  2. Hallo

    Problemstellung: Ich möchte eine Verlinkung nur einblenden, wenn eine Datei auf dem Server vorhanden ist. Da diese Sache auf einem Authoring-Tool für Lernanwendungen aufsitzt, kann ich nur Javascript verwenden und (zumindest vermute ich das sehr stark) nicht ohne weiteres weitere Bibliotheken aufsetzen. Um die Dinge beim Namen zu nennen: Es geht um Captivate und die Frage, ob die Datei "a10.pdf" vorhanden ist.

    Hier mein letzter Versuch:

    var request = new XMLHttpRequest();
    request.open('POST','a10.pdf', true);
    

    Du stellst einen Anfrage an eine PDF-Datei, die auf dem Server liegt. Auch wenn PDF aktive Elemente, also Programmcode haben kann, wird dieses PDF mit an Sicherheit grenzender Wahrscheinlichkeit mit deinem Aufruf keinen Code ausführen und damit auch nicht die von dir ausgewerteten Rückgabewerte erzeugen. Damit langet deine vom Status abhängige Verzweigung immer im Else-Zweig.

    if (request.status >= 200 && request.status < 300) {
    cp.show("a10_but");
             alert('a10.pdf vorhanden');
          } else {
    cp.hide("a10_but");
             alert('a10.pdf NICHTvorhanden');
          }; 
    

    Du brauchst auf dem Server ein ausführbares Skript, z.B. ein PHP-Skript. Dieses kannst du mit deinem XMLHTTPRequest aufrufen, wobei du den gewünschten Dateinamen als Parameter übergibst. Das serverseitige Skript prüft, ob die Datei vorhanden ist und gibt den passenden Status, den du in deinem JS-Skript auswerten kannst, zurück.

    var tmp=new Image;
        tmp.src='http://xyz.de/test/a10.pdf';
        if(tmp.complete)       
            alert("Datei vorhanden");       
        else       
        alert("Datei nicht vorhanden");
    

    Das ist etwas ganz anderes. Du erzeugst hier ein neues Bild und befüllst es dann mit einer Serverressource als Nutzdaten.

    Tschö, Auge

    --
    Wo wir Mängel selbst aufdecken, kann sich kein Gegner einnisten.
    Wolfgang Schneidewind *prust*
    1. Hallo

      Ich korrigiere mein Vorposting.

      var request = new XMLHttpRequest();
      request.open('POST','a10.pdf', true);
      

      Du stellst einen Anfrage an eine PDF-Datei, die auf dem Server liegt. Auch wenn PDF aktive Elemente, also Programmcode haben kann, wird dieses PDF mit an Sicherheit grenzender Wahrscheinlichkeit mit deinem Aufruf keinen Code ausführen und damit auch nicht die von dir ausgewerteten Rückgabewerte erzeugen. Damit langet deine vom Status abhängige Verzweigung immer im Else-Zweig.

      Also, wie Linuchs schon schrieb, musst du zuerst einmal eine vollständige URL angeben. Zweitens muss die Anfrage, wie Linuchs ebenfalls, wenn auch etwas verklausuliert, schon schrieb, auch gesendet werden. Ich habe mir mal mit Hilfe der MDN so ein Beispiel zusammengeschraubt.

       function reqListener () {
        console.log(this.responseText);
      }
      
      var oReq = new XMLHttpRequest();
      oReq.addEventListener("load", reqListener);
      oReq.open("GET", "http://www.example.org/daten/irgendein.pdf");
      oReq.send();
      

      Wenn du das tust und einmal in eine Konsole (z.B. die von Firebug) schaust, stellst du fest, dass mit dieser Anfrage dein Status aber das Dokument angefordert und auch ausgeliefert wird.

      if (oReq.status >= 200 && oReq.status < 300) {
        alert('irgendein.pdf vorhanden');
      } else {
        alert('irgendein.pdf NICHT vorhanden');
      }
      

      Ich erhalte mit meinem Beispiel die Meldung 'irgendein.pdf vorhanden' und direkt im Anschluss wird mir auch das PDF übertragen. Das landet allerdings, weil ich damit nichts anfange, im Nirwana. Um nur das Vorhandensein einer Datei abzufragen, eignet sich immer noch der Tip:

      Du brauchst auf dem Server ein ausführbares Skript …

      Mit einem solchen Skript kannst du genau steuern, was passiert und was zurück gegeben wird.

      var tmp=new Image;
          tmp.src='http://xyz.de/test/a10.pdf';
          if(tmp.complete)       
              alert("Datei vorhanden");       
          else       
          alert("Datei nicht vorhanden");
      

      Das ist etwas ganz anderes. Du erzeugst hier ein neues Bild und befüllst es dann mit einer Serverressource als Nutzdaten.

      … nur, dass das mit einer PDF-Datei natürlich nicht funktioniert. Das ist halt kein Bild.

      Tschö, Auge

      --
      Wo wir Mängel selbst aufdecken, kann sich kein Gegner einnisten.
      Wolfgang Schneidewind *prust*
      1. Hi,

        Um nur das Vorhandensein einer Datei abzufragen, eignet sich immer noch der Tip:

        Du brauchst auf dem Server ein ausführbares Skript …

        warum so umständlich? Ändere einfach die Request-Methode von GET auf HEAD. Dann bekommst du dieselben Meta-Informationen wie beim GET, nur dass der Dateiinhalt nicht übermittelt wird. Das spart also Bandbreite und Wartezeit.

        EDIT: Mal wieder einer meiner berühmten Vergleiche aus dem richtigen Leben.

        Kunde im Baumarkt zum Verkäufer: "Mich interessiert der Rasenmäher EM-618. Würden Sie mir bitte mal ein Gerät zeigen?"
        Verkäufer verschwindet im Lager, schleppt eine große Kiste und stellt sie ab: "Bitte sehr."
        Kunde: "Danke, ich wollte nur mal die technischen Daten auf dem Karton lesen."

        Das war GET. Und jetzt dasselbe mit HEAD.

        Kunde im Baumarkt zum Verkäufer: "Mich interessiert der Rasenmäher EM-618. Würden Sie mir bitte mal die technischen Daten geben?"
        Verkäufer verschwindet im Lager, kommt mit einem leeren, flachen Karton wieder: "Bitte sehr."
        Kunde: "Danke, genau das wollte ich wissen."

        /EDIT

        Mit einem solchen Skript kannst du genau steuern, was passiert und was zurück gegeben wird.

        Ja, wenn die gewünschte Information mit einem einfachen HTTP-Request auf die fragliche Ressource nicht zu bekommen ist. Aber die Auskunft über das Vorhandensein kriegt man ja auf jeden Fall, normalerweise sogar die Größe im Content-Length-Header. Wobei ich nicht sicher weiß, ob man mit dem XHR-Objekt auch auf die Response-Header zugreifen kann.

        So long,
         Martin

        --
        Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
        - Douglas Adams, The Hitchhiker's Guide To The Galaxy
      2. Danke für die Erläuterungen. :) Ich probiere das schnellstmöglich aus.

  3. var request = new XMLHttpRequest();
    request.open('POST','a10.pdf', true);
    if (request.status >= 200 && request.status < 300)
    

    denn die Meldung ist jedes mal, egal ob die Datei vorhanden ist oder nicht, "a10.pdf NICHTvorhanden".

    Ja, ist doch klar. Wenn ich zu dir sage: "Bitte bring ein Brot mit" und sofort nachschaue, ob das Brot schon da ist, ist die Antwort immer NEIN.

    1. var request = new XMLHttpRequest();
      request.open('POST','a10.pdf', true);
      if (request.status >= 200 && request.status < 300)
      

      Da fehlt Einiges. Ich mache es so:

        request.open('post', url, true);            // Request öffnen
        request.send(null);                         // Request senden
        request.onreadystatechange = zeigeHelptext; // Request auswerten
      ...
      function zeigeHelptext( )
      {
        // http://www.w3schools.com/ajax/ajax_xmlhttprequest_onreadystatechange.asp
        // The onreadystatechange event is triggered every time the readyState changes.
        if ( request.readyState == 4 && request.status == 200 )
        {
          document.getElementById( "helptext" ).innerHTML     = request.responseText;
          document.getElementById( "helptext" ).style.display = "block";
        }
      }
      

      Info:

      onreadystatechange
      Stores a function (or the name of a function) to be called automatically each time the readyState property changes
      
      readyState
      Holds the status of the XMLHttpRequest. Changes from 0 to 4:
      0: request not initialized
      1: server connection established
      2: request received
      3: processing request
      4: request finished and response is ready
      
      status
      200: "OK"
      404: Page not found
      

      Also warte den readyState == 4 ab und prüfe dann auf status == 200 Datei geladen oder status == 404 Datei nicht erreichbar.

      Linuchs

      1. Im Grunde haben mir hier ALLE Antworten ein Stückchen weitergeholfen. Die von Linuchs war in Kombination mit einige spätabendliche Lektionen in einem Crashkurs "Javascript" am aufschlussreichsten. Ich verstehe allmählich was ich tue ... ;)

        Linuchs' Variante funktioniert ganz prima, für mich genügt die Abfrage des headers, auf die Martin verwiesen hat. Da eine komplette Lösung - für mich - noch nirgends auffindbar war und ich vielleicht bei jemand anderem den Frustfaktor senken kann, hier mal beide Varianten komplett mit Skripting in einer HTML-Datei:

        <!doctype html>
        <html>
        <head>
        <meta charset="utf-8">
        <title>XMLHttpRequest mit Rückmeldung - Test - Nur Header</title>
        <script type="text/javascript">
        <!--
        function ZeigeVerberge( )
        {
        // http://www.w3schools.com/ajax/ajax_xmlhttprequest_onreadystatechange.asp
        // The onreadystatechange event is triggered every time the readyState changes.
          if ( request.readyState == 4 && request.status == 200 )
          {
            alert ('JA. Datei vorhanden! Hier dann der Code zum Einblenden der Elemente');
          }
          else {
               alert ('NEIN. Datei nicht vorhanden! Sofern nicht Anfangs global ausgeblendet hier Code zum Ausblenden der Elemente');
               }
        }
        
        function checkdatei(x) {
        request = new XMLHttpRequest(); // Definition des Request
        url = ('temp/' + x); // Hier wird zusammengesetzt, was abgefragt werden soll, z. B. 'temp/test.pdf'
        request.open('head',url, true); // Request öffnen ... url ist eine Variable. Bei direktem Aufruf statt dessen 'http://domain.de/datei,xyz' einschließlich Anführungszeichen
        request.send(null); // Request senden                         
        request.onreadystatechange = ZeigeVerberge; // Request auswerten
        }
        //-->
        </script>
        
        </head>
        
        <body onLoad="checkdatei('test.pdf')">
        <div id="Inhalt">Test XMLHttpRequest: Gibt alert Platzhalter aus, je nachdem, ob eine Datei da ist oder nicht:<br>
        Falls nein: 2 mal NEIN<br>
        Falls ja: 1 mal NEIN, nach laden des headers dann 1 mal JA.</div>
        </body>
        </html>
        

        ODER

        <!doctype html>
        <html>
        <head>
        <meta charset="utf-8">
        <title>XMLHttpRequest mit Rückmeldung - Test</title>
        <script type="text/javascript">
        <!--
        function zeigeHelptext( )
        {
        // http://www.w3schools.com/ajax/ajax_xmlhttprequest_onreadystatechange.asp
        // The onreadystatechange event is triggered every time the readyState changes.
          if ( request.readyState == 4 && request.status == 200 )
          {
            alert ('Hier dann der Code zum Einblenden der Elemente');
        	document.getElementById( "helptext" ).innerHTML     = request.responseText;
            document.getElementById( "helptext" ).style.display = "block";
          }
          else {
        	  alert ('Sofern nicht Anfangs global ausgeblendet hier Code zum Ausblenden der Elemente');
          }
        }
        function checkdatei() {
        request = new XMLHttpRequest();
        request.open('post','http://www.domain.de/temp/test.pdf', true); // Request öffnen
        request.send(null); // Request senden                         
        request.onreadystatechange = zeigeHelptext; // Request auswerten
        }
        //-->
        </script>
        
        </head>
        
        <body onLoad="checkdatei()">
        <div id="helptext">Antwort des Scripts bzw. Inhalt der Datei hier</div>
        </body>
        </html>
        

        Der Code dürfte in Verbindung mit den mir zuvor von den anderen Usern gegebenen Erklärungen hoffentlich selbtserklärend sein. Von mir nur der Hinweis, dass sowohl ein vollständiger URL (http://www.domain/temp/test.pdf wie im zweiten Beispiel) als auch ein relativer (erstes Beispiel) funktioniert. Außerdem noch die Warnung, dass das Ergebnis des Requests offensichtlich im Browser-Cache vorhanden ist.

        Soweit, so gut. Die Sache hat allerdings den Haken, dass sie in meinem Authoring-Umfeld NICHT mehr funktioniert. :( Offensichtlich kann dort Code nur chronologisch runtergenudelt werden. Aber ich bin immerhin ein Stück weiter :) ... und dieses Problem gehört dann vermutlich definitiv nicht mehr in dieses Forum.

        1. Ich bin kein Ajax-Meister, aber ich glaube, dass dies hier ein Problem sein kann:

          if ( request.readyState == 4 && request.status == 200 ) {
             // ok
          } else {
            // fehler
          }
          

          Grund: Die readyStates durchlaufen die Werte von 0-4, wobei 2="has been sent", 3="in progress" und 4="complete" bedeutet. Mit readyState 2 müsste dein EventHandler eigentlich immer aufgerufen werden. Und dann läufst Du in den Fehlerfall.

          Besser sollte dies sein, damit im Fall von readyState != 4 gar nichts geschieht.

          if ( request.readyState == 4 ) {
             if ( request.status == 200 ) {
                // ok
             } else {
               // fehler
             }
          }
          

          Rolf

    2. @@Linuchs

      Wenn ich zu dir sage: "Bitte bring ein Brot mit"

      „Bitte bring ein Brot mit und wenn’s Eier gibt, bringste sechs mit!“

      [Mann kommt vom Einkauf nach Hause]

      „Aber Liebling, warum hast du denn sechs Brote gekauft?“
      „Na – es gab Eier!“

      LLAP 🖖

      --
      “The best way to help people learn: answer their coding question an hour later, they’ll have likely figured it out by then.” —Todd Motto
      Selfcode: sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
      1. Alternativ-Text