19

I am working on a frontend application in React that connects to a middleware service written in Spring boot. I am attempting to call an endpoint from the front end as follows:

return axios.post('http://localhost:8085/workshop/client/createClient', {username})
.then((response) => {
  console.log('Success')
})
.catch((error) => console.log(error));

Whenever I make the request in my browser I get the following errors:

OPTIONS http://localhost:8085/workshop/client/createClient 401 ()

Failed to load http://localhost:8085/workshop/client/createClient: Response for preflight has invalid HTTP status code 401.

As far as I understand, this is because the preflight request is being blocked by my middleware application. Having read a bit online about enabling this, I have added a CorsFilter to my spring boot application:

@Slf4j
public class CORSFilter implements Filter {
  private static final String ONE_HOUR = "3600";

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
  }

  @Override
  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    HttpServletResponse response = (HttpServletResponse) res;
    response.setHeader("Access-Control-Allow-Origin", "*");
    response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
    response.setHeader("Access-Control-Max-Age", ONE_HOUR);
    response.setHeader("Access-Control-Allow-Headers", "X-Requested-With,Origin,Content-Type, Accept, x-device-user-agent, Content-Type");

    if (req instanceof HttpServletRequest) {
       HttpServletRequest httpServletRequest = (HttpServletRequest) req;
       if (httpServletRequest.getHeader(HttpHeaders.ORIGIN) != null
          && httpServletRequest.getMethod().equals(HttpMethod.OPTIONS.name())
          && httpServletRequest.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD) != null) {
          log.debug("Received an OPTIONS pre-flight request.");
          return;
       }
    }
    chain.doFilter(req, res);
  }

  @Override
  public void destroy() {
  }
}

And

@Configuration
public class MvcConfiguration {

 @Bean
 public FilterRegistrationBean corsFilter() {
   FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
   filterRegistrationBean.setFilter(new CORSFilter());
   filterRegistrationBean.addUrlPatterns("/*");
   filterRegistrationBean.setOrder(0);
   return filterRegistrationBean;
 }
}

Here is an example of the endpoint:

 @PostMapping("/createClient")
 public ResponseEntity<?> createClient(@RequestBody CreateClientDto clientDto) {
    try {
     ...
     return new ResponseEntity<>(responseBody, OK);
    } catch (Exception e ...) {}
  }

Any help would be greatly appreciated :)

Update: I had the url slightly wrong for the request (hence the 404). I have updated the error message. I still seem to be having CORS issues.

These are the response headers that I can see in the dev tools:

Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:access-control-allow-credentials, access-control-allow-methods, access-control-allow-origin, allow, content-type
Access-Control-Allow-Methods:POST
Access-Control-Allow-Origin:http://localhost:3000
Allow:GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Content-Length:0
Date:Thu, 01 Mar 2018 14:06:38 GMT
Expires:0
Pragma:no-cache
Strict-Transport-Security:max-age=31536000 ; includeSubDomains
Vary:Origin
WWW-Authenticate:Basic realm="Spring"
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block

And the request headers:

OPTIONS /workshop/client/createClient HTTP/1.1
Host: localhost:8085
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://localhost:3000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
Access-Control-Request-Headers: access-control-allow-credentials,access-control-allow-methods,access-control-allow-origin,allow,content-type
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en;q=0.9,en-US;q=0.8,da;q=0.7
1
  • The 404 seems to indicate that the URL http://localhost:8085/createClient is not found. Commented Mar 1, 2018 at 12:04

6 Answers 6

15

I also had this issue, but allow me to give a straight forward answer in a simpler communication manner.

First and foremost, you have to tell your server (Spring boot java), about the client (Reactjs ) URL.

For example, most of the times spring boot uses http://localhost:8080 and Reactjs uses http://localhost:3000.

So you have to navigate to the controller in Spring boot java and allow the URL of Reactjs to be given the permission for accessibility in the server (Spring boot). This will help you get rid of the CORS issue.

How do we do this in Spring boot? simply we add the @CrossOrigin annotation specifying the Reactjs URL link as below:

For example :

    @GetMapping("/orphans")
    @CrossOrigin(origins = "http://localhost:3000")
    Iterable<Student> read() {
        return studentService.findAll();
    }

The method above is to list all the orphans, so I gave Reactjs URL link permission then I got rid of the CORS issue.

Happy coding.

Sign up to request clarification or add additional context in comments.

Comments

7

Controller.java

Refer to the below sample code to resolve this issue.

@CrossOrigin(origins = "http://localhost:3000")
@RequestMapping(value="/sample", method = RequestMethod.GET, produces = "application/json")

public Student getStudent(){
}

Comments

7

add below line of code in fetch

  export function getData(endpoint = '/', request = {}) {
    let url = endpoint;
    let req = Object.assign(
      {
        headers: {
          Accept: 'application/json',
          'Content-Type': 'application/json',
          'Access-Control-Allow-Origin': '*',
        },
      },
      request
    );
    console.log('url,req', url, req);
    return fetch(url, req).then(handleResponse).catch(handleErrors);
  }

And Add below line below Rest Controller class

@RestController
@CrossOrigin(origins = "*", allowedHeaders = "*")
class TestController{}

hope this would helpful :)

2 Comments

@CrossOrigin(origins = "", allowedHeaders = "") this is worked for me thank you
Access-Control-Allow-Origin is a response header, not a request header
2

This is a standard CORS issue, this basically means that user agent i.e. http://localhost:3000 doesn't have permissions to access resources at http://localhost:8085. You can learn more about it at https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS.

Your request headers should exactly map to server rules. Keeping any parameter as * won't work.

For e.g., if your request header has following:

Access-Control-Request-Method: POST
Access-Control-Request-Headers: <your custom headers>

Then, server rules show map your request header:

Access-Control-Request-Method: GET, PUT, DELETE, POST
Access-Control-Request-Headers: <your custom headers>

Let me know if it helps!

2 Comments

Thanks for your help. Unfortunately I am still seeing the same issue. Am I missing a header for the request or the response? I have updated the question with the headers that I can see in the dev tools
Sorry for replying late to your comment, I have been busy for a couple of days. With your update on your question, I can see that your request headers doesn't match with the server rules. For e.g., Access-Control-Allow-Headers doesn't match with Access-Control-Allow-Header. The rules set at server and sent in your request headers must be exactly the same
2

The issue seems to be resolved. I was missing the Accept request header (thanks @Anadi Sharma), and I also had the spring-boot-starter-security as a dependency, which seemed to be returning unauthorised. I also didn't need the CorsFilter, in the end I just used the @CrossOrigin annotation on the endpoint.

3 Comments

what do you mean by Accept request Header please.
explain more please or add the updated code.
can you please explain with updated codes, how did you solve ?
2

I was able to resolve this by adding bean configuration in server side (spring boot app) to allow origins.

@SpringBootApplication
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

    @Bean
    public WebMvcConfigurer configure() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry reg) {
                reg.addMapping("/**").allowedOrigins("*");
            }
        };
    }

}

1 Comment

Thats an easy one. Thanks @Ruchira

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.