Spring Cloud - Zuul Proxy is producing a No 'Access-Control-Allow-Origin' ajax response
Asked Answered
C

7

17

Startup Appplication:

@SpringBootApplication
@EnableZuulProxy
public class ZuulServer {

     public static void main(String[] args) {
         new SpringApplicationBuilder(ZuulServer.class).web(true).run(args);
     }
 }

My YAML file is like this:

server:
   port:8080

spring:
   application:
      name: zuul

eureka:
client:
  enabled: true
    serviceUrl:
       defaultZone: http://localhost:8761/eureka/



zuul:
    proxy:
       route:
         springapp: /springapp

I have a microservice application (on port 8081) called springapp and has some rest services. Below is my client UI app:

    <html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script type="text/javascript" src="js/libs/jquery/jquery.min.js" ></script>
    </head>
    <body>
        <script type="text/javascript">
            $.ajax({
                url: 'http://localhost:8080/zuul/springapp/departments',
                type: 'GET'
            }).done(function (data) {
                consoe.log(data);
                document.write(data);
            });
        </script>        

    </body>
</html>

But I get a

XMLHttpRequest cannot load http://localhost:8080/zuul/springapp/departments. No
    'Access-Control-Allow-Origin' header is present on the requested
    resource. Origin 'http://localhost:8383' is therefore not allowed access.

This UI HTML5 app is on http://localhost:8383/SimpleAPp/index.html. CORS, CORS, CORS... Please help. BTW the http://localhost:8080/zuul/springapp/departments returns a json list as supposed to when on the browser address bar. The spring.io blog here says that there is no need for a filter because the zuulproxy takes care of that but I don't know why it is not working for me.

Carpometacarpus answered 23/2, 2015 at 9:36 Comment(0)
P
47

Adding this piece of code to your class annotated with @EnableZuulProxy should do the trick.

@Bean
public CorsFilter corsFilter() {
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    final CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("OPTIONS");
    config.addAllowedMethod("HEAD");
    config.addAllowedMethod("GET");
    config.addAllowedMethod("PUT");
    config.addAllowedMethod("POST");
    config.addAllowedMethod("DELETE");
    config.addAllowedMethod("PATCH");
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
}
Puentes answered 7/4, 2016 at 23:44 Comment(5)
This works, thanks!! But, shouldn't this be the default behavior?Gibun
Can you please provide complete code.. I stuck in these issue from a very long timeVeery
@Veery whats the problem you are having this is the complete code to set the CORS Filter.Puentes
@GrinishNepal I just want to know where is the right place to put these code, I tried multiple combinations. My project structure is like Angular6 -> ApiGateway -> microservicesVeery
Dude. If had million dollars and u behind me, we would get drunk today. God bless.Onanism
A
6

I had a similar problem, with Angular Web app consuming RESTful services implemented by Spring Boot with Zuul and Spring Security.

None of the above solutions worked. I realized that the problem was NOT in Zuul, but in Spring Security.

As the official documentation (CORS with Spring Security) states, when using Spring Security, CORS must be configured prior to Spring Security.

Finally, I was able to integrate Grinish Nepal's (see prior answers) solution into a solution that works.

Without further ado, here is the code that enables CORS with Spring Security and Zuul:


    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        //irrelevant for this problem
        @Autowired
        private MyBasicAuthenticationEntryPoint authenticationEntryPoint;

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    //configure CORS -- uses a Bean by the name of     corsConfigurationSource (see method below)
                    //CORS must be configured prior to Spring Security
                    .cors().and()
                    //configuring security - irrelevant for this problem
                    .authorizeRequests()
                        .anyRequest().authenticated()
                        .and()
                    .httpBasic()
                    .authenticationEntryPoint(authenticationEntryPoint);

            //irrelevant for this problem
            http.addFilterAfter(new CustomFilter(),
                    BasicAuthenticationFilter.class);
        }

        //The CORS filter bean - Configures allowed CORS any (source) to any 
        //(api route and method) endpoint
        @Bean
        CorsConfigurationSource corsConfigurationSource() {
            final UrlBasedCorsConfigurationSource source = new     UrlBasedCorsConfigurationSource();
            final CorsConfiguration config = new CorsConfiguration();
            config.setAllowCredentials(true);
            config.addAllowedOrigin(CorsConfiguration.ALL);
            config.addAllowedHeaders(Collections.singletonList(CorsConfiguration.ALL));
            config.addAllowedMethod("OPTIONS");
            config.addAllowedMethod("HEAD");
            config.addAllowedMethod("GET");
            config.addAllowedMethod("PUT");
            config.addAllowedMethod("POST");
            config.addAllowedMethod("DELETE");
            config.addAllowedMethod("PATCH");
            source.registerCorsConfiguration("/**", config);
            return source;
        }

        //configuring BA usernames and passwords - irrelevant for this problem
        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws     Exception {
           ...
        }
    }
Altamira answered 17/10, 2017 at 17:1 Comment(3)
Do you add this class in the application with zuul or the application which has the microservice?Rempe
@Mate with these solution I am getting pop-up which asks me to enter username , password. Please help me with these settingVeery
@Veery My solution above is for people who are trying to enable CORS while using Zuul and Spring Security, with some method of authentication. My example uses .httpBasic() authentication, which is why your browser will ask for username and password in a popup. If you don't need Spring Security, use the accepted answer or try my solution with removing all the code under comments: //configuring security - irrelevant for this problem, //irrelevant for this problem, //configuring BA usernames and passwords - irrelevant for this problem. Hope this helps, and let me know if it works.Robbynrobe
H
5

When your application runs on http://localhost:8383 then you can only make AJAX-calls to http://localhost:8383. Zuul doesn't and cannot change that.

What Zuul can do is mapping requests for e.g. http://localhost:8383/zuul/ to http://localhost:8080/zuul/. But your browser would have to call http://localhost:8383/zuul/springapp/departments and you have to configure that mapping.

Heuristic answered 23/2, 2015 at 14:21 Comment(3)
Thanks a lot. That worked for me :) My other question now is: What would you do if you have an angular js app wrapped in Cordova/Phonegap and using static files in the app instead of serving the files from the proxy server? I ask because my solution as of now only works because the static file with the ajax request resides on the ZuulProxy server.Carpometacarpus
I have a solution for the immediately above angular.js scenario. I added a CORS Filter as shown here to the ZuulProxy. So any request that goes to the ZuulProxy from the same domain as the proxy or from some other source will be allowed :)Carpometacarpus
If I assume correct, CORS Filter only works if the app is hosted on root (/) context. If the app is hosted on any other context you need to fallback on enabling CORS specifc to that servlet container.Chaffer
W
4

Just adding the following to the configuration worked for me

zuul:
    ignoredHeaders: Access-Control-Allow-Credentials, Access-Control-Allow-Origin
Wiersma answered 23/4, 2020 at 0:53 Comment(0)
P
3

I had the same issue, and i have fixed by adding CorsFilter bean

  @Bean
  public FilterRegistrationBean corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(0);
    return bean;
  }

And adding zuul's properties this code

zuul:
  sensitiveHeaders:
  ignored-headers: Access-Control-Allow-Credentials, Access-Control-Allow-Origin

You can find more detail about the issue here

Poulenc answered 6/2, 2019 at 17:34 Comment(0)
D
2

That's just the browser telling you that you breached its common origin policy (see Wikipedia entry and a huge amount of material on the internet, none of which is really relevant to the tags you added). You can either teach the browser that it is OK to load resources from a different address by servicing the CORS pre-flight checks (e.g. in a Filter) or load the HTML through the proxy (hint: the latter is much easier and less error prone).

Dakotadal answered 23/2, 2015 at 10:31 Comment(2)
Thanks for trying to answer but the reason I added the tags is because of the @EnableZuulProxy which is from the spring cloud. On this post on the spring.io blog they say that there is no need for that Filter which you mentioned because the ZuulProxy does a reverse proxy for the consuming client. Hope this makes sense.Carpometacarpus
Yes, but as @zeroflagL says below, that just means you have to send all requests through the proxy.Dakotadal
F
1

For those still having issue even when @Bean CorsFilter is added, check if the controller is also annotated with @CrossOrigin, this duplication of CORS, at controller level and at Zuul proxy is probably causing the issue.

Forefoot answered 1/10, 2021 at 4:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.