Reputation: 115
I have just started learning javascript, so please bear with me.
I'm have two html pages, say page1.html and page2.html. There are two buttons on both pages, 'next' and 'previous'. The idea is to open the next or previous page in the sequence. I was opening the new page by setting window.location.href
to the new file://
url. Except, of course when it tries to access page0 or page3, the browser shows file not found.
So I decided to try using fetch
and opening the new page only if the response.ok
is true
. This is my function handling the button.onclick
:
fetch(url).then(function(response) {
if (response.ok) {
window.location.href = url;
}
else {
alert("This is the last page.");
}
});
It works as I expect when the page exists (it opens the page). But when it doesn't the console shows 1 warning and 1 error (and doesn't change the page at all, doesn't trigger the alert
either):
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at file:///path/to/page3.html. (Reason: CORS request not http).
TypeError: NetworkError when attempting to fetch resource.
I searched around and found that non-http requests are blocked for security reasons (don't allow webpages to access local files on whim).
The thing that confuses me is that even when the file exists (page1 or page2) it's still a non-http request and yet it works. Why is it being blocked only when the file doesn't exist? And why am I getting a NetworkError
alongside it?
Upvotes: 1
Views: 104
Reputation: 1075209
fetch
(in browsers, anyway) has this to say about file:
URLs:
For now, unfortunate as it is, file URLs are left as an exercise for the reader.
When in doubt, return a network error.
In general, fetch
doesn't succeed with a file:
URL. Sadly, it appears that on Firefox, if the file being fetched exists, it succeeds, but if it doesn't exist, it throws a network error. (I guess that makes some sense, it's not like it could return an HTTP status code; it's not using HTTP.) On Chrome and Edge, it always fails, regardless of whether the file exists. In some browsers (like Chrome) the older XMLHttpRequest
also doesn't (but on other browsers, like Firefox, it does).
The major difference between fetch
/XMLHttpRequest
and setting the href
of the page is that in the former case, code on Page A is able to read the content of Page B; but in the latter case, it can't — it can go to Page B, but it can't read Page B's content. Page A is replaced by Page B.
If XMLHttpRequest
had been standardized in the security environment we now live in, I suspect it too would specifically disallow access to file:
URLs.
Since Firefox treats the file not existing as a NetworkError, your code — for Firefox only — could be:
// With file: URLs, this ONLY works in Firefox
fetch(url)
.then(function(response) {
if (!response.ok) {
throw new Error("HTTP status " + response.status);
}
})
.then(function() {
window.location.href = url;
})
.catch(error => {
alert("This is the last page.");
});
Or perhaps:
fetch(url)
.then(function(response) {
return response.ok;
})
.catch(function() {
return false;
})
.then(function(flag) {
if (flag) {
window.location.href = url;
} else {
alert("This is the last page.");
}
});
You could use arrow functions there. I haven't because you didn't, but:
fetch(url)
.then(response => response.ok)
.catch(() => false)
.then(flag => {
if (flag) {
window.location.href = url;
} else {
alert("This is the last page.");
}
});
Upvotes: 2