background

The reason for this article is to resolve a cross-domain request for a business center page. Because the business center, or the ability to reuse services, is now very much advocated, it is common to request resources from different domain names under the domain name of a unified business center. So this is bound to cause cross-domain problems.

Cross domain

Cross-domain actually stems from a security restriction that browsers place on javascript (also known as the same origin policy). By default, you can access only resources under the same protocol, domain name, and port.

The actual scene

The front desk of the business center has two functions. Function A needs to request the background API of the user center and the price center to complete it. Function B needs to request the API of user center, policy center, organization center and customer center.

For example, if function A requests the user center, A cross-domain problem occurs when A request is sent from bussiness.center.com to the user.com domain.

A single service across domain solution

Using Filter

In the case of the Spring Cloud Gateway, we need to add cross-domain Filter implementation logic to the Gateway. Of course, cross-domains can be handled in any Spring 5.0+ service in the following manner.

  • Interface WebFilter

package org.springframework.web.server;

// Requires Spring 5.0+
public interface WebFilter {

	Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain);

}
Copy the code

Interface description: Intercepting chain processing contracts for Web requests, which can be used to implement cross-domain, application-independent requirements, such as security, timeouts, etc.

There are two ways to do this according to WebFilter.

** Custom Filter implements WebFilter **

@Component
public class CorsFilter implements WebFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
        //TODO adds configuration in response header to allow cross-domain,
        / / such as Access - Control - Allow - Origin
        returnwebFilterChain.filter(serverWebExchange); }}Copy the code

Spring’s self-implemented cross-domain filter CorsWebFilter is recommended for cross-domain processing

Cross-domain is handled by configuring the CorsConfigurationSource

@Bean
CorsWebFilter corsWebFilter(a) {
    CorsConfiguration corsConfig = new CorsConfiguration();
    corsConfig.setAllowedOrigins(Arrays.asList("http://allowed-origin.com"));
    corsConfig.setMaxAge(8000L);
    corsConfig.addAllowedMethod("PUT");
    corsConfig.addAllowedHeader("Baeldung-Allowed");

    UrlBasedCorsConfigurationSource source =
            new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/ * *", corsConfig);

    return new CorsWebFilter(source);
}

Copy the code
  • InterFace GlobalFilter

The idea of using SprinCloud Gateway GlobalFilter to solve cross-domain problems is basically the same as that of self-implementing WebFiler. It is important to note that the order in which the various filters of the gateway are executed is concerned, and I recommend that you configure GlobalFilter across domains to be executed first.

@Component
public class GlobalCorsFilter implements GlobalFilter.Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {        				//TODO adds configuration in response header to allow cross-domain,
        / / such as Access - Control - Allow - Origin
        return chain.filter(exchange);
    }

    @Override
    public int getOrder(a) {
        returnOrdered.HIGHEST_PRECEDENCE; }}Copy the code
Use @crossorigin on Controller to handle cross-domains

The API for a particular Controller can be handled across domains through annotations.

@CrossOrigin(value = { "http://allowed-origin.com" }, allowedHeaders = { "Baeldung-Allowed" }, maxAge = 900 )
@RestController
public class CorsOnClassController {

    @PutMapping("/cors-enabled-endpoint")
    public Mono<String> corsEnabledEndpoint(a) {
        // ...
    }

    @CrossOrigin({ "http://another-allowed-origin.com" })
    @PutMapping("/endpoint-with-extra-origin-allowed")
    public Mono<String> corsEnabledWithExtraAllowedOrigin(a) {
        // ...
    }

    // ...
}
Copy the code
Enable CORS on global configuration

The addCorsMappings() method is also recommended to define the global CORS configuration by overriding the WebFluxConfigurer implementation. You need @enableWebFlux to import the Spring WebFlux configuration.

@Configuration
@EnableWebFlux
public class CorsGlobalConfiguration implements WebFluxConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry corsRegistry) {
        corsRegistry.addMapping("/ * *")
                .allowedOrigins("http://allowed-origin.com")
                .allowedMethods("PUT")
                .maxAge(3600); }}Copy the code

Cross-domain solutions for business centers

Whether it’s through Filter, adding HttpReponse Header to allow cross-domain request headers, or overriding WebFluxConfigurer to configure cross-domain. This is a good solution for a single service.

But for the front desk of the business center, it is very undesirable and very frustrating to configure so many domain names and corresponding apis for the middle Stage project.

So the establishment of the middle layer is particularly important and key. We use Nginx as a reverse proxy server to solve cross-domain problems.

Nginx. conf, upstream and server can be used to resolve cross-domain issues, load balancing, health checks, etc.

upstream user {
    zone upstream_dynamic 64k;

    server backend1.example.com      weight=5;
    server backend2.example.com:8080 fail_timeout=5s slow_start=30s;
    server 192.0.2.1                 max_fails=3;
    server backend3.example.com      resolve;
    server backend4.example.com      service=http resolve;

    server backup1.example.com:8080  backup;
    server backup2.example.com:8080  backup;
}

upstream policy {
    zone upstream_dynamic 64k;

    server backend1.example.com      weight=5;
    server backend2.example.com:8080 fail_timeout=5s slow_start=30s;
    server 192.0.2.1                 max_fails=3;
    server backend3.example.com      resolve;
    server backend4.example.com      service=http resolve;

    server backup1.example.com:8080  backup;
    server backup2.example.com:8080  backup;
}

server {
    listen 80;
    server_name bussiness.center.com;
  
    location /api/user {
        proxy_pass http://user;
        health_check;
    }
  
    location /api/policy {
        proxy_passhttp://policy; health_check; }}Copy the code

Refer to the article

www.baeldung.com/spring-webf…