Cross Subdomain(www.example.com => api.example.com)Cross Main Domain(www.exp1.com => api.exp2.com)

Cross Subdomain(www.example.com => api.example.com): When the frontend domain and backend domain are different but share the same main domain, such as www.example.com requesting an API from api.example.com.
You only need to configure the response header in api.example.com Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin

Cross Main Domain(www.exp1.com => api.exp2.com): When the frontend domain and backend domain are completely different, such as www.exp1.com requesting an API from api.exp2.com
1. You need to configure the response header in the backend api.exp2.com Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin
2. Return response headers for all OPTIONS requests to the api.exp2.com domain Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin
3. The response status code for OPTIONS requests to api.exp2.com must be 204;

options Response Header:

  • Access-Control-Allow-Headers
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Origin

Response Header:

  • Access-Control-Allow-Headers
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Origin

WEB Cross-Origin/CORS Verification Process and Configuration Examples

Table of Contents


Cross-Origin Exceptions

Access to XMLHttpRequest at '' from origin '' 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 you encounter the above exception, you can use the following tool for online testing:


Browser Cross-Origin Resource Sharing (CORS) Verification Process

The browser's Cross-Origin Resource Sharing (CORS) verification process is mainly divided into two situations: simple requests and preflight requests:

1. Simple Request

Requests that meet the following conditions are considered simple requests:

  • Request methods: GET, POST, or HEAD
  • Request headers only include: Accept, Accept-Language, Content-Language, Content-Type
  • Content-Type values are limited to:
    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded

Verification process:

  1. The browser sends the request directly, adding the Origin field in the request header
  2. The server returns a response, which needs to include the following response headers:
    • Access-Control-Allow-Origin
    • Access-Control-Allow-Credentials (optional)
    • Access-Control-Expose-Headers (optional)

2. Preflight Request

Requests that do not meet the simple request conditions require preflight, such as:

  • Using PUT, DELETE, and other methods
  • Sending JSON format data
  • Custom request headers

Verification process:

  1. The browser first sends an OPTIONS request for preflight
    • Includes Origin field
    • Access-Control-Request-Method field
    • Access-Control-Request-Headers field (if there are custom headers)
  2. The server responds to the preflight request, returning:
    • Access-Control-Allow-Origin
    • Access-Control-Allow-Methods
    • Access-Control-Allow-Headers
    • Access-Control-Max-Age (optional, caching time for preflight results)
    • Access-Control-Allow-Credentials (optional)
  3. After the preflight passes, the browser sends the actual request
    • The actual request follows the same verification process as a simple request
    • The server returns the actual response data

3. Common Response Headers Explanation

  • Access-Control-Allow-Origin: Allowed domain names, such as * or specific domain names
  • Access-Control-Allow-Methods: Allowed request methods, such as GET, POST, PUT, DELETE
  • Access-Control-Allow-Headers: Allowed request headers
  • Access-Control-Allow-Credentials: Whether to allow sending cookies
  • Access-Control-Max-Age: Validity period of preflight requests
  • Access-Control-Expose-Headers: Response headers that the browser is allowed to access

4. Important Notes

  1. If you need to send cookies, you need to:
    • Set withCredentials = true on the frontend
    • Set Access-Control-Allow-Credentials = true on the server
    • Access-Control-Allow-Origin cannot be set to *, it must specify a specific domain name
  2. Caching of preflight requests:
    • Set caching time through Access-Control-Max-Age
    • The same request will not send a preflight request again during the cache period
  3. Security considerations:
    • Not recommended to use the * wildcard
    • Recommended to explicitly configure allowed domain names, methods, and request headers
    • Perform identity verification for sensitive operations

1. NGINX Configuration


server {
      listen 80; # 监听的端⼝
      server_name localhost; # 域名或ip
      location / { # 访问路径配置
        #允许跨域请求的域,* 代表所有
        add_header 'Access-Control-Allow-Origin' *;
        #允许带上cookie请求
        add_header 'Access-Control-Allow-Credentials' 'true';
        #允许请求的方法,比如 GET/POST/PUT/DELETE
        add_header 'Access-Control-Allow-Methods' *;
        #允许请求的header
        add_header 'Access-Control-Allow-Headers' *;

        if ($request_method = 'OPTIONS') {
          return204;
        }
        root /usr/share/nginx/html;# 根⽬录
        index index.html index.htm; # 默认⾸⻚
      }
      error_page 500 502 503 504 /50x.html; # 错误⻚⾯
      location = /50x.html {
        root html;
      }
}

2. JAVA Configuration

2.1. Spring Boot Annotation Method

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RestController;

@RestController
@CrossOrigin(origins = "*", maxAge = 3600)
public class TestController {
    // Add @CrossOrigin annotation to the controller class
    // origins = "*" means allowing access from all domain names
    // maxAge = 3600 means the validity period of the preflight request is 3600 seconds
}

2.2. Global Configuration


import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")    // Path allowed for cross-origin access
                .allowedOrigins("*")    // Source allowed for cross-origin access
                .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")    // Allowed request methods
                .maxAge(3600)    // Preflight request cache time
                .allowedHeaders("*")    // Allowed headers
                .allowCredentials(true);    // Whether to send cookies
    }
}

2.3、Spring Security Configuration


import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()
          // Other security configurations
            .csrf().disable();
    }
    
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

3、PHP Configuration

# Add at the entry file
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: *");

4、NODEJS Configuration

4.1、nodejs express Configuration


// ... existing code ...
// 1. Import modules
const express = require('express')
 
// 2. Create server
let app = express()
// Import cors (needs to be installed: this sets response header res.setHeader("Access-Control-Allow-Origin", "*"))
var cors = require('cors')
app.use(cors())

4.2、nodejs koa2 Configuration

const cors = require('koa2-cors');
const Koa = require('koa');

const app = new Koa();

app.use(cors({
  exposeHeaders: ['Authenticate'],
  credentials: true,
  allowMethods: ['GET', 'POST', 'DELETE', 'PUT', 'PATCH'],
  allowHeaders: ['Content-Type', 'Authorization', 'Accept'],
}));

curl Test Command

curl -i -X OPTIONS 'https://****************' \
-voa /dev/null \
-H 'Origin: http://********* (cross-origin address)' \
-H "Access-Control-Request-Method: GET (method)"