skip to Main Content

I am writing a local html family tree.
Since the site is supposed to contain many personal pages that will take me a long to write, I want my browser to display in grey the links to the pages that have still not been created (everything here is on the server side in the project directory).
It seemed it was only a matter of checking if a file existed and changing the colour of the link with javascript, but it turned out to be much more complicated than I thought. I read several solutions in google to check if a file exists, and all of them failed. One of them is the following:

function LinkCheck(url) {
  var http = new XMLHttpRequest();
  http.open('HEAD', url, false);
  http.send();
  return http.status !== 404;
}

This failed. Then I tried to debug, and change the function to:

function LinkCheck(url) {
  var http = new XMLHttpRequest();
  http.open('HEAD', url, false);
  http.send();
  //return http.status !== 404;
  return false;
}

This should have worked unconditionally since the function returns "false" in any case. But this one failed too.
Then I disabled the "send" part:

function LinkCheck(url) {
  var http = new XMLHttpRequest();
  http.open('HEAD', url, false);
  //http.send();
  //return http.status !== 404;
  return false;
}

An this worked! So, the problem is the function http.send() that causes a failure. Any insight?

Note: I tried with Firefox and Chrome, with the same results.

EDIT 1:
The JavaScript code that actually uses this function is:

if (LinkCheck("Abraham_page.html")){} else {
  document.getElementById("Abraham_link_id").style.color = "gray";
} 

Where "Abraham_page.html" may be located inside the same directory as the page containing the calling function (but actually don’t exist).

Edit 2:
I’m not use to the debugger tool, but it seems the relevant message is:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at file:///C:/Tex-Dir/Tex_Work/User/html/genealogy/Abraham_page.html. (Reason: CORS request not http).

2

Answers


  1. In order to return a boolean answer using XMLHttpRequest#send, like you are trying to do in your LinkCheck function, you need to first realize that whether you use .onreadystatechange or .onload, the return statement will only return from the callback function, and not from LinkCheck. In order to be able to pass the server response back to your code, you’d need to pass this function a callback and call it when ready, something along the lines of:

    function LinkCheck(url, cb) { // <- note cb
      var http = new XMLHttpRequest();
      http.open('HEAD', url, false);
      http.onreadystatechange = () => {
        if (http.readyState === XMLHttpRequest.DONE) {
          cb(http.status !== 404) // pass the boolean response 
        }
      };
      http.send();
    }
    

    and somewhere in your code you’d have:

    LinkCheck('my/link', (isLinkOk) => {
      if(isLinkOk){
        // ... do what you need to do
      }
    })
    

    But then the same problem sort of propagates to the rest of your code and make code messy, hard to read, hard to debug, hard to maintain.

    You could try instead using Fetch API, which is based on Promises and can produce somewhat less nested code when used with async/await:

    async function LinkCheck(url) {
      await result = fetch(url);
    
      const json = await result.json(); // depends on actual response ofc
      const isOK = /* your logic here */
    
      return isOK
    }
    

    Then your code looks much intuitive, much like what you expected from XMLHttpRequest.

    With fetch you can also use raw promises with .then() – but it terms of code nesting this won’t make it any different from what you currently have with XMLHttpRequest

    Login or Signup to reply.
  2. You may want to use fetch for that. It’s relatively simple to detect the 404 (not found) error result, throw an error if so and do something to the href in html when it occurs. Here the very handy service from https://httpstat.us/ is used to retrieve errors:

    document.querySelectorAll(`a`).forEach(
      lnk => {
        fetch(lnk.href, {method: `head`})
          .then(resp => {
            if (!resp.ok) { throw Error(resp.statusText ?? `Error fetching`); }
            return true;
        })
        .catch((err) => {
            console.log(`${lnk.href} ${err}`);
            lnk.style.color = `grey`;
            lnk.style.fontWeight = `bold`;
        })
      }
    );
    <!-- not found (404) -->
    <div><a href="http://httpstat.us/404">file a 404</a></div>
    <div><a href="http://httpstat.us/404">file b 404</a></div>
    <div><a href="https://google.com/">cors restricted, can't do</a></div>
    <div><a href="https://sdn.nicon.nl/Tests/test.html">no cors restriction, <i>can</i> do</a></div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search