简体   繁体   中英

CORS blocks mutation in GraphQL Yoga

I am working here with a graphql prisma backend and a graphql yoga express server on top of that. In the frontend, I am trying to call a signout mutation but its blocked by the CORS policy. Though I have added cors settings in my graphql yoga server, I keep getting this error. GraphQL Queries are working fine but Mutations are being blocked. My frontend URL is ' http://localhost:7777 ' and yoga server is running at ' http://localhost:4444/ '. The Error was:

Access to fetch at 'http://localhost:4444/' from origin 'http://localhost:7777' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

[Network error]: TypeError: Failed to fetch

GraphQL Yoga Server Cors Config:

server.start(
{
    cors: {
        credentials: true,
        origin: [process.env.FRONTEND_URL],
    },
},
deets => {
    console.log(
        `Server is now running on port http://localhost:${deets.port}`
    );
}
);

Mutation:

// import React, { Component } from 'react';
import { Mutation } from 'react-apollo';
import styled from 'styled-components';
import gql from 'graphql-tag';
import { CURRENT_USER_QUERY } from './User';
import { log } from 'util';

const SIGN_OUT_MUTATION = gql`
mutation SIGN_OUT_MUTATION {
    signout {
        message
    }
}
`;

const SignOutBtn = styled.button`
color: ${props => props.theme.textMedium};
padding: 10px;
margin-right: 20px;
text-align: center;
font-family: garamond-light;
border: 1px solid ${props => props.theme.textMedium};
border-radius: 5px;
transition: background-color 0.5s ease;
transition: color 0.5s ease;
:hover {
    background: ${props => props.theme.textMedium};
    color: ${props => props.theme.white};
}
`;

const Signout = props => (
<Mutation
    mutation={SIGN_OUT_MUTATION}
    refetchQueries={[{ query: CURRENT_USER_QUERY }]}
>
    {signout => (
        <SignOutBtn
            onClick={() => {
                console.log("comes here")
                signout();
            }}
        >
            Sign Out
        </SignOutBtn>
    )}
</Mutation>
);
export default Signout;

Please tell me what I am doing wrong here. Thanks in Advance.

The solution to the problem was to write a middleware that sets appropriate response headers so that the fetch doesn't fail.

server.express.use(function(req, res, next) {
  res.header('Access-Control-Allow-Origin', 'http://localhost:7777');
  res.header(
    'Access-Control-Allow-Headers',
    'Origin, X-Requested-With, Content-Type, Accept'
  );
  next();
});

The above is the yoga express server middleware used to solve the problem.

What I had to do was pass the origin an array of string values. As well as set the new origin PAST_FRONTEND_URL in heroku

 server.start( { cors: { credentials: true, origin: [process.env.FRONTEND_URL, process.env.PAST_FRONTEND_URL], }, }, deets => { console.log(`Server is now running on port http://localhost:${deets.port}`); } );

I had the same problem and it was solved with this

server.start(
  {
    cors: {
      credentials: true,
      origin: [process.env.FRONTEND_URL],
      methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
      preflightContinue: false,
      optionsSuccessStatus: 204
    }
  },
  server => {
    console.log(`Server is running on http://localhost/${server.port}`);
  }
);

Adding this middleware helped in my case:

server.express.use((req, res, next) => {
  res.header('Access-Control-Allow-Credentials', true)
  next()
})

Server Application must add Access-Control-Allow-Origin: YOUR_DOMAIN to the response header and the browser will not complain about it.

You can use a middleware to achieve it.

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "YOUR-DOMAIN"); // update to match the domain you will make the request from
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

OR

const cors =  require('cors')
const corsOptions = {
    origin: [
        
        "http://YOUR-DOMAIN"
    ],
    credentials: true
}
app.use(cors(corsOptions))

But wait;! I already done these steps but still the problem exist ;(

if after these steps the issue still exist.

then it's because of corrupted response .

maybe your server throw an exception while sending the response or maybe it restart and the response not sent to client completely. or maybe some problem with your ISP or VPN which block some requests. :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM