I know questions like that have been asked tons of times already but I still was not able to find a solution or even an explanation for that manner.
I work on a project that needs the best possible resolution on YouTube thumbnails. I used the following url https://i.ytimg.com/vi/VIDEOID/maxresdefault.jpg however I found out that on rare occasions this does not work and I get a placeholder image, and a status of 404, back. In that case I would like to use https://i.ytimg.com/vi/VIDEOID/hqdefault.jpg.
To check if an image exists I tried to make a fetch-request using JavaScript:
const url = "https://i.ytimg.com/vi/VIDEOID/hqdefault.jpg"
fetch(url).then(res => console.log(res.status))
But I get an error stating that the CORS-Header 'Access-Control-Allow-Origin' is missing. I tried setting it and several other headers I found but to no avail. It only works if I send the request in no-cors mode, but then the status is always 0 and all the other data seems to be missing aswell.
I also tested the request in Postman where it worked and even copied the JavaScript-Fetch-Snipped that Postman gave me:
var requestOptions = {
method: 'GET',
redirect: 'follow'
};
fetch("https://i.ytimg.com/vi/VIDEOID/maxresdefault.jpg", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
I read that this is a problem from the Server and Youtube is restricting this, but why does it work in Postman and why does it work when using <cfhttp> in ColdFusion? Also the status-code even shows up in the console within the CORS-Error message...
Why? explained:
The CORS policy is implemented in browsers to allow sharing resources between websites while preventing websites from attacking each other:
SOP (same origin policy) prevents web sites from attacking each other but does not allow any sharing between origins.
CORS (cross origin resource sharing) relaxes SOP restrictions, but requires specific server headers/configuration.
These policies only apply inside a browser. Presumably Postman and Coldfusion work because they are making direct HTTP requests outside the context of a browser script. Which leads to how to work-around CORS restrictions...
Solutions:
3 Ways to Fix the CORS Error — and How the Access-Control-Allow-Origin Header Works explains how to bypass CORS restrictions. They all work by manipulating the request headers/origin:
Browser extension. (Not sure if this still works in 2022. Only works if user installs browser extension.)
3rd party request proxy. (The proxy linked in the demo is now limited due to abuse.)
Build your own proxy.
Realistically, option #3 is the only real solution. SvelteKit endpoints make it super simple to proxy requests.
Following code is working properly for me and I am always getting 200 status ok
Something similar implementation can be done
//import fetch from 'node-fetch';
const fetch = require('node-fetch');
loaddata();
async function loaddata(){
var Headers="{headers: {'Access-Control-Allow-Origin': '*'}";
var requestOptions = {
method: 'GET',
redirect: 'follow',
};
const response = await fetch('https://i.ytimg.com/vi/9DCwyuH29SI/hqdefault.jpg',requestOptions,Headers);
console.log(response);
}
Related
I am trying to get the csv data from a url from the nrel developer website. Unfortunately I can't work with json data because it will send it to the email, while the csv file is immediate. I could achieve this using vba using the following:
With req
.Open "GET", parsedUrl, False
.SetRequestHeader "Content-Type", "text/csv;"
.Send
End With
result = Split(req.responseText, Chr(10))
'do work with result
However, working with javascript and the excel addins documentation I am not able to store the csv data on a variable.
I tried the following code
const res = await fetch(tmyUrl, {
method: "GET",
headers: {
"Content-Type": "text/csv;",
},
});
if (!res.ok) throw new Error("There was a problem trying to get the the weather data.");
But this gives me the following error:
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I also tried adding the following:
mode: "no-cors"
But the res.ok is false and the body seems to be empty.
It takes a little time to process this request, so I know it is doing something in the background.
I also could trigger the download using downloadjs but I don't need to download, I just need to temporary store the data in a variable.
Any help or advice please.
I also tried adding [mode: "no-cors"] but... the body seems to be empty.
This is precisely because you're calling the endpoint with mode: no-cors. This behavior is well-documented, and discussed at length in this SO thread. From the linked MDN page (emphasis mine):
no-cors — Prevents the method from being anything other than HEAD, GET or POST, and the headers from being anything other than simple headers. If any ServiceWorkers intercept these requests, they may not add or override any headers except for those that are simple headers. In addition, JavaScript may not access any properties of the resulting Response. This ensures that ServiceWorkers do not affect the semantics of the Web and prevents security and privacy issues arising from leaking data across domains.
The reason you're seeing CORS errors in the first place is that the server that's responding to your request has deliberately been configured this way to prevent these types of requests on its resources. You can bypass this by making the request to your own server (which allows CORS), which can then proxy the ultimate request to the service and return the response to your client. There used to be several prominent drop-in services that provided this functionality, but most have gone by the wayside due to service abuse (CORS Anywhere and Whatever Origin, to name two).
There still exists one service that appears to still proxy these types of requests - All Origins. Drop in your URL according to their documentation to effectively bypass this restriction:
const res = await fetch(`https://allorigins.win/get?url=${encodeURIComponent(tmyUrl)}`, {
method: "GET",
headers: {
"Content-Type": "text/csv;",
},
});
Be forewarned, you really, really need to trust this service to use this in any project. By routing your requests through their service, you are implicitly allowing them to snoop on your traffic uninhibited and potentially return malicious content to your clients. It's a much better idea to do this on your own server that you control.
We have been encountering inconsistent client errors with a single-page JavaScript application making fetch requests. Of note, they are all same-origin requests.
let request = new Request(url, options);
...
window.fetch(request)
.then(response => response.json())
.then(data => ...)
.catch(error => ...)
Around 5% of the promises are rejecting with the following error despite the server and the browser receiving a 200 OK response:
TypeError: Failed to fetch
I'm stumped... All of my searches lead to discussions about CORS errors. That doesn't seem to apply given these are all same-origin requests. What is causing the fetch to throw the TypeError?
I can confirm using the Network tab in Chrome DevTools that the fetch request completes with a 200 OK response and valid JSON. I can also confirm that the URLs are same-origin. I can also confirm that there are no CORS pre-flight requests. I have reproduced this issue on Chrome 66 and Safari 11.1. However, we've received a stream of error reports from a mix of Chrome and Safari versions, both desktop and mobile.
EDIT:
This does not appear to be a duplicate of the linked question as we are not sending CORS requests, not setting mode: "no-cors", and not setting the Access-Control-Allow-Origin header.
Additionally, I re-ran tests with the mode: 'same-origin' option set explicitly. The requests are (still) successful; however, we (still) receive the intermittent TypeError.
I know that this is an old issue, but after searching the entire evening I want to share my findings so you can spend your time better.
My web app also worked well for most users but from time to time visitors received the error mentioned in the question. I'm not using any complicated infrastructure (reverse proxy etc.) setup nor do I communicate with services on a different domain/protocol/port. I'm just sending a POST request to a PHP-File on the same server where the React app is served from.
The short answer: My problem was that I've sent the request to the backend by using an absolute URL, like https://my-fancy-domain.com/funky_service.php. After changing this to a relative path like /funky-service.php the issue was gone.
My explanation: Most users come to the site without www in the URL, but some users actually do type this part in their address bars (www.my-fancy...). It turned out that the www is part of the origin, so when these users submit the form and send post requests to https://my-fancy... it's technically another origin. This is why the browser expects CORS headers and sometimes even sends an OPTIONS preflight request. When you use a relative path in your JavaScript-Code the post request will also include the www-part (uses the origin from the address bar) -> same-origin -> no CORS hassle. As it only affects visitors that come with the www to your site it also explains the fact that it worked for most users even with the absolute URL.
Also important to know: The request fails in the browser/ JavaScript-Code but is actually sent to the backend (very ugly!).
Let me know if you need more information. Actually, it is very simple but hard to explain (and to find)
The issue could be with the response you are receiving from back-end. If it was working fine on the server then the problem could be with the response headers. Check the Access-Control-Allow-Origin (ACAO) in the response headers. Usually react's fetch API will throw fail to fetch even after receiving response when the response headers' ACAO and the origin of request won't match.
Ref: Getting "TypeError: failed to fetch" when the request hasn't actually failed
I have seen dozens of questions on SO and different blogs talking about this with "answers" -- all to no avail.
I have a React.js app on my local machine (Ubuntu 16.04). Locally, I try to test it by running npm start and it opens up the browser to http://localhost:3000.
On one page, I am trying to access my PHP api which is on my shared hosting server.
Chrome and Firefox both say that it fails due to server not having Access-Control-Allow-Orgin.
Exact Message:
Failed to load http://---/api/v1/categories: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost.com:3000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
localhost.com/:1 Uncaught (in promise) TypeError: Failed to fetch
However, upon my php server entry point I do have:
header("Access-Control-Allow-Orgin: *");
header("Access-Control-Allow-Methods: *");
Here is where I make my api call in my react app:
componentDidMount() {
var options = {
method: 'get',
headers: {
"Access-Control-Request-Headers": "*",
"Access-Control-Request-Method": "*"
},
}
// I have since removed the headers from the options as advised in the comments
fetch('http://---/api/v1/categories', options)
.then(results => {
return results.json();
}).then(data => {
let categories = data.map((category) => {
return(
// edited out
)
})
this.setState({categories: categories});
})
}
}
I have tried this on both Chrome and Firefox; I have also tried to alias my server away from localhost. I have tried the no-cors approach, which does get me access -- but breaks everything of course. I have tried with and without passing headers along with my fetch request.
UPDATE:
I did get it to work by installing this Chrome plugin. I feel this is a workaround and would like to know if there is a coding answer here.
I'm an idiot.
Origin was misspelled as Orgin.
This typo has existed in my project for almost three years. This was the first time I needed to use cross-domain access.
header("Access-Control-Allow-Methods: *");
Should be:
header("Access-Control-Allow-Methods: GET, POST, HEAD, OPTIONS, PUT, DELETE, PATCH");
...and any other methods you intend to accept.
I'm trying to access Medium's API to get a list of public stories from a user. However, I'm getting a CORS error when I try to access it on the client side. Here's the code
axios.get(`http://medium.com/#ev/latest`).then((res)=>{
console.log(res.data)
})
.catch((error)=>{
console.log(error)
})
I did some research and found this github issue, but couldn't find any workaround. Is there any way to make this request work on the client side?
You can get the HTML from https://medium.com/#ev/latest by making your request through a CORS proxy — either a proxy you set up yourself or else just by using a public open CORS proxy like https://cors-anywhere.herokuapp.com/. Here’s how to do it using the standard Fetch API:
fetch("https://cors-anywhere.herokuapp.com/https://medium.com/#ev/latest")
.then(res => res.text())
.then(text => document.querySelector("div").innerHTML = text)
.catch(error => console.log(error))
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div></div>
For more details — including how to set up your own CORS proxy on Heroku in just a few minutes, see How to use a CORS proxy to get around “No Access-Control-Allow-Origin header” problems in the answer at No 'Access-Control-Allow-Origin' header is present on the requested resource—when trying to get data from a REST API.
Incidentally, if instead you want JSON, you can try https://medium.com/#ev/latest?format=json but you’ll find that what you get back isn’t actually valid JSON; instead it starts out like this:
])}while(1);</x>{"success":true,"payload":{"user":{"userId":"268314bb7e7e","name"…
Apparently that’s intentional, per a comment from a Medium developer in their issue tracker:
The JSON page is not intended to be used as a read API. The extra code is there to support our own use and is a standard technique to avoid JSON hijacking.
That’s trivial to work around, though: Just first handle the response as text in your client code, and strip out the ])}while(1);</x> from the start of it, and then run JSON.parse on what remains.
But as far as using Axios to get the response as text, I think you’ll find it’s not going to work as expected even if you make the request through a CORS proxy; try this:
axios.get('https://cors-anywhere.herokuapp.com/http://medium.com/#ev/latest', {
responseType: 'text'
})
.then(res => console.log(res.data))
.catch(error => console.log("ERROR"))
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
The code hits the catch because apparently even when you specify responseType: 'text', Axios apparently still tries the parse the response as JSON:
This is because JSON.parse is always tried in the response, even if responseType is text. We should fix that indeed.
And https://medium.com/#ev/latest is HTML, not JSON, so running JSON.parse on it will fail.
That’s why the first snippet in this answer uses the Fetch API instead (you can get text back with it).
This is currently not allowed by Medium (There server doesn't respond with the Access-Control-Allow-Origin header). Probably because of security concerns.
As suggested in the GitHub issue you linked to, a possible solution will be to tunnel the request to Medium through your server (as proxy). You can create an endpoint on your server (i.e. http://my-server.com/get-medium/#ev/latest) that will retrieve the requested Medium page (on the server side) and will return it to the client side.
This comment to the issue describes a way to do that using AWS Lambda as the proxy server - link
I am currently developing a dashboard which consumes the Mention API. However, I am having difficulties due to the CORS policy.
If the dashboard is opened on Chrome or another browser that has a strict CORS policy, they make a preflight OPTIONS request each time, but these appear to not be supported by the Mention API.
Therefore, every time I do something like:
this.mentionAPI = axios.create({
baseURL: 'https://web.mention.net/api/accounts/my-account-id',
headers: {
'Authorization': 'Bearer my-access-token',
}
});
this.mentionAPI.get('/alerts')
.then((response) => {
console.log(response);
})
.catch((response) => {
console.log(response);
});
I get a response with the status 405 Method Not Allowed. This suggests that the OPTIONS requests are not handled by the Mention API at all.
Naturally, in my case I can just make sure that the browser is configured to not perform preflight requests. After all, my use case prescribes just one client, which I control completely. Alternatively, I could build a server-side service to make the requests on my behalf, however it seems like hunting a fly with cannon, since client side JavaScript is more than capable to perform everything else.
Any help on this issue would be really appreciated. Perhaps I'm misunderstanding how the API is intended to be consumed?