admin管理员组

文章数量:1127036

I can hit this endpoint, via Postman and it returns JSON

Additionally I am using create-react-app and would like to avoid setting up any server config.

In my client code I am trying to use fetch to do the same thing, but I get the error:

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost: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.

So I am trying to pass in an object, to my Fetch which will disable CORS, like so:

fetch('', { mode: 'no-cors'})
  .then(blob => blob.json())
  .then(data => {
    console.table(data);
    return data;
  })
  .catch(e => {
    console.log(e);
    return e;
  });

Interestingly enough the error I get is actually a syntax error with this function. I am not sure my actual fetch is broken, because when I remove the { mode: 'no-cors' } object, and supply it with a different URL it works just fine.

I have also tried to pass in the object { mode: 'opaque'} , but this returns the original error from above.

I belive all I need to do is disable CORS.. What am I missing?

I can hit this endpoint, http://catfacts-api.appspot.com/api/facts?number=99 via Postman and it returns JSON

Additionally I am using create-react-app and would like to avoid setting up any server config.

In my client code I am trying to use fetch to do the same thing, but I get the error:

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost: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.

So I am trying to pass in an object, to my Fetch which will disable CORS, like so:

fetch('http://catfacts-api.appspot.com/api/facts?number=99', { mode: 'no-cors'})
  .then(blob => blob.json())
  .then(data => {
    console.table(data);
    return data;
  })
  .catch(e => {
    console.log(e);
    return e;
  });

Interestingly enough the error I get is actually a syntax error with this function. I am not sure my actual fetch is broken, because when I remove the { mode: 'no-cors' } object, and supply it with a different URL it works just fine.

I have also tried to pass in the object { mode: 'opaque'} , but this returns the original error from above.

I belive all I need to do is disable CORS.. What am I missing?

Share Improve this question edited Jun 22, 2019 at 8:59 sideshowbarker 87.9k29 gold badges214 silver badges211 bronze badges asked Apr 6, 2017 at 17:36 dwwwdwww 5,5983 gold badges14 silver badges12 bronze badges 1
  • 1 Does this answer your question? Handle response - SyntaxError: Unexpected end of input when using mode: 'no-cors' – Cees Timmerman Commented Nov 20, 2020 at 9:15
Add a comment  | 

14 Answers 14

Reset to default 820

mode: 'no-cors' won’t magically make things work. In fact it makes things worse, because one effect it has is to tell browsers, “Block my frontend JavaScript code from seeing contents of the response body and headers under all circumstances.” Of course you never want that.

What happens with cross-origin requests from frontend JavaScript is that browsers by default block frontend code from accessing resources cross-origin. If Access-Control-Allow-Origin is in a response, then browsers relax that blocking and allow your code to access the response.

But if a site sends no Access-Control-Allow-Origin in its responses, your frontend code can’t directly access responses from that site. In particular, you can’t fix it by specifying mode: 'no-cors' (in fact that’ll ensure your frontend code can’t access the response contents).

However, one thing that will work: if you send your request through a CORS proxy.

You can also easily deploy your own proxy to Heroku in just 2-3 minutes, with 5 commands:

git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master

After running those commands, you’ll end up with your own CORS Anywhere server running at, for example, https://cryptic-headland-94862.herokuapp.com/.

Prefix your request URL with your proxy URL; for example:

https://cryptic-headland-94862.herokuapp.com/https://example.com

Adding the proxy URL as a prefix causes the request to get made through your proxy, which:

  1. Forwards the request to https://example.com.
  2. Receives the response from https://example.com.
  3. Adds the Access-Control-Allow-Origin header to the response.
  4. Passes that response, with that added header, back to the requesting frontend code.

The browser then allows the frontend code to access the response, because that response with the Access-Control-Allow-Origin response header is what the browser sees.

This works even if the request is one that triggers browsers to do a CORS preflight OPTIONS request, because in that case, the proxy also sends back the Access-Control-Allow-Headers and Access-Control-Allow-Methods headers needed to make the preflight successful.


I can hit this endpoint, http://catfacts-api.appspot.com/api/facts?number=99 via Postman

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS explains why it is that even though you can access the response with Postman, browsers won’t let you access the response cross-origin from frontend JavaScript code running in a web app unless the response includes an Access-Control-Allow-Origin response header.

http://catfacts-api.appspot.com/api/facts?number=99 has no Access-Control-Allow-Origin response header, so there’s no way your frontend code can access the response cross-origin.

Your browser can get the response fine and you can see it in Postman and even in browser devtools—but that doesn’t mean browsers expose it to your code. They won’t, because it has no Access-Control-Allow-Origin response header. So you must instead use a proxy to get it.

The proxy makes the request to that site, gets the response, adds the Access-Control-Allow-Origin response header and any other CORS headers needed, then passes that back to your requesting code. And that response with the Access-Control-Allow-Origin header added is what the browser sees, so the browser lets your frontend code actually access the response.


So I am trying to pass in an object, to my Fetch which will disable CORS

You don’t want to do that. To be clear, when you say you want to “disable CORS” it seems you actually mean you want to disable the same-origin policy. CORS itself is actually a way to do that — CORS is a way to loosen the same-origin policy, not a way to restrict it.

But anyway, it’s true you can—in your local environment—do suff like give a browser runtime flags to disable security and run insecurely, or you can install a browser extension locally to get around the same-origin policy, but all that does is change the situation just for you locally.

No matter what you change locally, anybody else trying to use your app is still going to run into the same-origin policy, and there’s no way you can disable that for other users of your app.

You most likely never want to use mode: 'no-cors' in practice except in a few limited cases, and even then only if you know exactly what you’re doing and what the effects are. That’s because what setting mode: 'no-cors' actually says to the browser is, “Block my frontend JavaScript code from looking into the contents of the response body and headers under all circumstances.” In most cases that’s obviously really not what you want.


As far as the cases when you would want to consider using mode: 'no-cors', see the answer at What limitations apply to opaque responses? for the details. The gist of it is:

  • In the limited case when you’re using JavaScript to put content from another origin into a <script>, <link rel=stylesheet>, <img>, <video>, <audio>, <object>, <embed>, or <iframe> element (which works because embedding of resources cross-origin is allowed for those)—but for some reason you don’t want to/can’t do that just by having the markup of the document use the resource URL as the href or src attribute for the element.

  • When the only thing you want to do with a resource is to cache it. As alluded to in What limitations apply to opaque responses?, in practice the scenario that’s for is when you’re using Service Workers, in which case the API that’s relevant is the Cache Storage API.

But even in those limited cases, there are some important gotchas to be aware of; see the answer at What limitations apply to opaque responses? for the details.


I have also tried to pass in the object { mode: 'opaque'}

There is no 'opaque' request mode — opaque is instead just a property of the response, and browsers set that opaque property on responses from requests sent with no-cors mode.

But incidentally the word opaque is a pretty explicit signal about the nature of the response you end up with: “opaque” means you can’t see into any of its details; it blocks you from seeing.

If you are trying to address this issue temporarily on your localhost, you can use this Chrome extension :

Allow CORS Access-Control-Allow-Origin

If you are using Express as back-end you just have to install cors and import and use it in

app.use(cors());.

If it is not resolved then try switching ports. It will surely resolve after switching ports

So if you're like me and developing a website on localhost where you're trying to fetch data from Laravel API and use it in your Vue front-end, and you see this problem, here is how I solved it:

  1. In your Laravel project, run command php artisan make:middleware Cors. This will create app/Http/Middleware/Cors.php for you.
  2. Add the following code inside the handles function in Cors.php:

    return $next($request)
        ->header('Access-Control-Allow-Origin', '*')
        ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    
  3. In app/Http/kernel.php, add the following entry in $routeMiddleware array:

    ‘cors’ => \App\Http\Middleware\Cors::class
    

    (There would be other entries in the array like auth, guest etc. Also make sure you're doing this in app/Http/kernel.php because there is another kernel.php too in Laravel)

  4. Add this middleware on route registration for all the routes where you want to allow access, like this:

    Route::group(['middleware' => 'cors'], function () {
        Route::get('getData', 'v1\MyController@getData');
        Route::get('getData2', 'v1\MyController@getData2');
    });
    
  5. In Vue front-end, make sure you call this API in mounted() function and not in data(). Also make sure you use http:// or https:// with the URL in your fetch() call.

Full credits to Pete Houston's blog article.

You can also set up a reverse proxy which adds the CORS headers using a self-hosted CORS Anywhere or Just CORS if you want a managed solution.

https://justcors.com/<id>/<your-requested-resource>
http://cors-anywhere.com/<your-requested-resource>

Very easy solution (2 min to config) is to use local-ssl-proxy package from npm

The usage is straight pretty forward:
1. Install the package: npm install -g local-ssl-proxy
2. While running your local-server mask it with the local-ssl-proxy --source 9001 --target 9000

P.S: Replace --target 9000 with the -- "number of your port" and --source 9001 with --source "number of your port +1"

Solution for me was to just do it server side

I used the C# WebClient library to get the data (in my case it was image data) and send it back to the client. There's probably something very similar in your chosen server-side language.

//Server side, api controller

[Route("api/ItemImage/GetItemImageFromURL")]
public IActionResult GetItemImageFromURL([FromQuery] string url)
{
    ItemImage image = new ItemImage();

    using(WebClient client = new WebClient()){

        image.Bytes = client.DownloadData(url);

        return Ok(image);
    }
}

You can tweak it to whatever your own use case is. The main point is client.DownloadData() worked without any CORS errors. Typically CORS issues are only between websites, hence it being okay to make 'cross-site' requests from your server.

Then the React fetch call is as simple as:

//React component

fetch(`api/ItemImage/GetItemImageFromURL?url=${imageURL}`, {            
        method: 'GET',
    })
    .then(resp => resp.json() as Promise<ItemImage>)
    .then(imgResponse => {

       // Do more stuff....
    )}

I had a similar problem with my browser debugger saying my response.body was null but fiddler and the developer tools show it as populated that turned out to be basically the same scenario as this. I was using a local Angular application hitting a Web Api service running on IISExpress. I fixed it by following the steps outlined here to find the correct applicationhost.config file to add a Access-Control-Allow-Origin header like so:

  <customHeaders>
    <clear />
    <add name="X-Powered-By" value="ASP.NET" />
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Headers" value="Content-Type" />
  </customHeaders>

If all the above solutions don't work, probably it's because of the file permissions as sometimes even if you have fixed the non-cors problem using Heroku or another way, it throws 403 forbidden error. Set the directory/file permissions like this:

Permissions and ownership errors A 403 Forbidden error can also be caused by incorrect ownership or permissions on your web content files and folders.

Permissions Rule of thumb for correct permissions:

Folders: 755

Static Content: 644

Dynamic Content: 700

I have to add some notes for anyone making CORS requests.

  • Make sure both websites use HTTPS. CORS only works over HTTPS if you want to set withCredentials: true and send over the cookie.
  • Configure CORS on the server side(eg, Nginx config).

Here is an example of Nginx config.

server {

    # CORS block BEGIN
    add_header 'Access-Control-Allow-Origin' $http_origin;
    add_header 'Access-Control-Allow-Headers' 'x-requested-with, Content-Type, origin, authorization, accept, client-security-token';
    add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,PATCH,DELETE';
    add_header 'Access-Control-Allow-Credentials' 'true';
    # CORS block END

}
  • $http_origin should only be used on the dev server. Replace it with your domain on the production server. For the rest, please continue your search.

References:

  • https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

in my case removing of previously added headers: { 'Content-Type': 'application/json' } solved similar issue and works for me with no any mode cors/no-cors.

of course my backend has proper Access-Control-Allow-Origin: * header added to the response.

fetch(url, {mode: 'cors'})

works for me.

Basically, fetch(url, {requestParameterDataObject})

The fetch JS documentation will have more info about the specific field names within the request parameters object. Here, we are using the request's mode field & setting it to 'cors'.

My final code:

useEffect(() => {
        // Loading while etching API data
        setIsLoading(true);

        fetch(url, {mode: 'cors'})
            .then((response) => response.json())
            .then((data) => {
                setData(data);

                // Turn off loading flag once data comes back
                setIsLoading(false);
            });
    }, [url]);

The most upvoted answer is the right approach of sending the request through CORS proxy. However, since Heroku no longer offers a free tier, the deployment part is a little bit outdated.

For a 2024 solution, you can host a CORS proxy yourself with Cloudflare Worker free tier using this repository: https://github.com/Zibri/cloudflare-cors-anywhere

However, be aware that there are daily requests limits when using Cloudflare Worker, so depending on your use case it might not be suitable for production use.

If you are looking for a production ready CORS proxy, you can check out Corsfix, it has unlimited monthly requests and supports request header overrides.

Here is an example of how to send request through the CORS proxy

fetch("https://proxy.corsfix.com/?<TARGET_URL>"); 

(I am affiliated with Corsfix)

If you’re using React, I recommend creating a new project with the following command:

npm create vite@latest project_name -- --template react

To address the CORS issue, update the vite.config.js file as follows:

export default defineConfig({
  plugins: [react()],
    server: {
      proxy: {
        '/api': {
          target: "http://localhost:3000"
        }
      }
    }
})

本文标签: javascriptTrying to use fetch and pass in mode nocorsStack Overflow