跨二级域名(www.example.com => api.example.com)跨主域名(www.exp1.com => api.exp2.com)

跨二级域名(www.example.com => api.example.com): 如前端的域名与后端的域名不同但是主域名是一致的,如www.example.com请求api.example.com的接口。
则只需要在api.example.com配置响应头 Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin

跨主域名(www.exp1.com => api.exp2.com): 如前端的域名与后端的域名不同,如www.exp1.com请求api.exp2.com的接口
1. 则需要在后端api.exp2.com配置响应头 Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin
2. 在针对api.exp2.com域名的所有的options请求都返回响应头 Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin
3. 则需要在api.exp2.com的options请求中的相应状态码为204才可;

options 响应头:

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

响应头:

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

WEB 跨域/CORS 验证过程及配置示例

目录


跨域异常

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. 出现以上异常可使用以下工具进行在线测试:


浏览器跨域资源共享(CORS)的验证过程

浏览器的跨域资源共享(CORS)验证过程主要分为简单请求和预检请求两种情况:

1. 简单请求(Simple Request)

满足以下条件的请求被视为简单请求:

  • 请求方法为:GET、POST 或 HEAD
  • 请求头只包含:Accept、Accept-Language、Content-Language、Content-Type
  • Content-Type 的值仅限于:
    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded

验证流程:

  1. 浏览器直接发送请求,并在请求头中添加 Origin 字段
  2. 服务器返回响应,需包含以下响应头:
    • Access-Control-Allow-Origin
    • Access-Control-Allow-Credentials(可选)
    • Access-Control-Expose-Headers(可选)

2. 预检请求(Preflight Request)

不满足简单请求条件的请求都需要预检,如:

  • 使用 PUT、DELETE 等方法
  • 发送 JSON 格式数据
  • 自定义请求头

验证流程:

  1. 浏览器首先发送 OPTIONS 请求进行预检
    • 包含 Origin 字段
    • Access-Control-Request-Method 字段
    • Access-Control-Request-Headers 字段(如有自定义头)
  2. 服务器响应预检请求,返回:
    • Access-Control-Allow-Origin
    • Access-Control-Allow-Methods
    • Access-Control-Allow-Headers
    • Access-Control-Max-Age(可选,预检结果缓存时间)
    • Access-Control-Allow-Credentials(可选)
  3. 预检通过后,浏览器发送实际请求
    • 实际请求与简单请求的验证流程相同
    • 服务器返回实际响应数据

3. 常见响应头说明

  • Access-Control-Allow-Origin:允许访问的域名,如 * 或具体域名
  • Access-Control-Allow-Methods:允许的请求方法,如 GET, POST, PUT, DELETE
  • Access-Control-Allow-Headers:允许的请求头
  • Access-Control-Allow-Credentials:是否允许发送 Cookie
  • Access-Control-Max-Age:预检请求的有效期
  • Access-Control-Expose-Headers:允许浏览器访问的响应头

4. 注意事项

  1. 如果要发送 Cookie,需要:
    • 前端设置 withCredentials = true
    • 服务端设置 Access-Control-Allow-Credentials = true
    • Access-Control-Allow-Origin 不能设为 *,必须指定具体域名
  2. 预检请求的缓存:
    • 通过 Access-Control-Max-Age 设置缓存时间
    • 缓存期内相同请求不再发送预检请求
  3. 安全考虑:
    • 不建议使用 * 通配符
    • 建议明确配置允许的域名、方法和请求头
    • 对敏感操作要进行身份验证

1、NGINX 配置


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 配置

2.1、Spring Boot 注解方式

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

@RestController
@CrossOrigin(origins = "*", maxAge = 3600)
public class TestController {
    // 在控制器类上添加@CrossOrigin注解
    // origins = "*" 表示允许所有域名访问
    // maxAge = 3600 表示预检请求的有效期为3600秒
}

2.2、全局配置方式


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("/**")    // 允许跨域访问的路径
                .allowedOrigins("*")    // 允许跨域访问的源
                .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")    // 允许请求方法
                .maxAge(3600)    // 预检间隔时间
                .allowedHeaders("*")    // 允许头部设置
                .allowCredentials(true);    // 是否发送cookie
    }
}

2.3、Spring Security 配置方式


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()
            // 其他安全配置
            .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 配置

#入口文件处添加
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: *");

4、NODEJS 配置

4.1、nodejs express 配置


//1.导入模块
const express = require('express')
 
//2.创建服务器
let app = express()
// 导入一个cors(需要下载:这是给响应头设置res.setHeader("Access-Control-Allow-Origin", "*"))
 
var cors = require('cors')
app.use(cors())

4.2、nodejs koa2 配置

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 测试命令

curl -i -X OPTIONS 'https://****************' \
-voa /dev/null \
-H 'Origin: http://*********(跨域地址)' \
-H "Access-Control-Request-Method: GET(动作)"