Issue
My application has a backend built with Spring Boot, and a frontend web application built with Angular and served by nginx. Nginx is configured to reverse-proxy requests to /api/ to the backend :
location /api/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://back:8080;
}
If nginx is running on the default port (80), I can access my application at http://myserver/ without issues. XHR calls to http://myserver/api/some/REST/resource work perfectly.
If I change nginx to listen to some other port (randomly : 9043), then all XHR calls fail with an error "Invalid CORS request". Which is unexpected, because only my frontend application is making calls to the API, and thanks to the reverse-proxy this API is served on the same host as the javascript files.
For it to function, I need to add this to my Spring application :
@Configuration
public class CorsConfig {
@Value("${url.base:''}")
private String urlBase;
@Value("${cors.allowed.origins:[]}")
private String[] allowedOrigins;
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping(urlBase + "/**")
.allowedOrigins(allowedOrigins)
.allowedMethods("*");
}
};
}
}
and then set cors.allowed.origin
s to http://myserver:9043/
in my configuration.
This works, but it is not practical if I'm going to :
- make the hostname and/or port dynamic (port is derived from the branch name during CI build, then the containers are deployed to a rancher cluster)
- hide the nginx behind a load-balancer (= another level of reverse-proxying)
Would there be a solution to fix this by doing any of the following :
- Have spring boot to ignore the port number when validating CORS requests ?
- Have nginx tweak the contents of the proxied request so that CORS validation by Spring succeeds ?
EDIT : some more details and example :
The services are dockerized :
- Frontend : nginx listens on port 80 inside the container, docker exposes it on the host as port 9043
- Backend : spring boot listens on 8080. The port is not exported by Docker, so it is only accessible from the frontend container, which has a link to the backend container.
It only works if the frontend is exposed to the outside world on port 80...
Solution
Add two http header in reverse request:
X-Forwarded-Proto
X-Forwarded-Port
to indecate the origin proto and ports (match the origin request).
see more: https://moi.vonos.net/java/spring-forward/
Answered By - JianrongChen