Spring MVC跨域设置

简介

出于安全方面考虑,浏览器发起请求时,会先检查同源策略(协议、主机、端口是否与当前页面相同),不匹配则认为是跨域请求。

CORS (Cross-Origin Resource Sharing)

CORS是一种机制,允许服务器声明哪些域(origin)可以访问其资源,从而绕过同源策略的限制。浏览器会发送预检请求(Preflight Request)以确定是否允许跨域访问。

Preflight请求

Preflight请求是跨域资源共享(CORS)中的一种机制,用于在实际请求之前发送一个预检请求。浏览器在发送某些类型的跨域请求(例如带有自定义标头的请求)之前,会自动发送一个OPTIONS请求,以获取目标服务器是否允许实际请求的权限。

预检请求包含一组查询信息,询问服务器是否允许实际请求。这些查询信息包括:

  • Access-Control-Request-Method: 表示实际请求中将使用的 HTTP 方法(例如 GET、POST)。
  • Access-Control-Request-Headers: 表示实际请求中将使用的自定义 HTTP 标头。

服务器收到预检请求后,会检查这些信息,然后决定是否允许实际请求。如果服务器允许,它会在响应中包含相应的 CORS 头(例如 Access-Control-Allow-Origin、Access-Control-Allow-Methods 等)。

这个预检请求机制有助于确保安全,因为它防止了潜在的恶意跨域请求。如果服务器支持并验证了预检请求,浏览器才会允许实际请求。

以下是一个预检请求的示例:

请求:

makefile 复制代码
OPTIONS /example/resource HTTP/1.1
Host: example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, Authorization

响应:

makefile 复制代码
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type, Authorization

Spring MVC跨域设置

浏览器发起Preflight请求,SpringMVC的处理流程为:
DispatcherServlet#doDispatch -> HttpRequestHandlerAdapter#handle -> AbstractHandlerMapping#handleRequest -> DefaultCorsProcessor#processRequest
DefaultCorsProcessor会根据当前配置的跨域规则,检查当前资源你是否允许发起的域访问,检查不通过时直接返回403 Forbidden,body为Invalid CORS request。

注解方式

可以在类,或者方法上使用@CrossOrigin(origins = "*", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.OPTIONS})

Filter模式

对于使用了Spring-Web而没有使用SpringMVC的项目,可以使用Spring提供的CorsFilter,它会拦截的Servlet请求,并添加一些允许跨域的头,以下是允许所有请求跨域的示例

java 复制代码
@Configuration
public class CorsConfig {

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

测试

可以使用以下html进行跨域测试

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>POST Request Form</title>
</head>
<body>

<h1>POST Request Form</h1>

<form id="postForm">
    <label for="url">URL:</label>
    <input type="text" id="url" name="url" value="http://xxx" style="width: 100%; margin-bottom: 10px;">
    
    <label for="postData">POST Data:</label>
    <textarea id="postData" name="postData" style="width: 100%; height: 100px; margin-bottom: 10px;">
{

}
    </textarea>
    
    <button type="button" onclick="sendPostRequest()">Send POST Request</button>
</form>

<script>
function sendPostRequest() {
    var url = document.getElementById("url").value;
    var postData = document.getElementById("postData").value;

    fetch(url, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: postData,
    })
    .then(response => response.json())
    .then(data => {
        console.log('Success:', data);
        alert('POST request sent successfully!');
    })
    .catch((error) => {
        console.error('Error:', error);
        alert('Error sending POST request!');
    });
}
</script>

</body>
</html>
相关推荐
王嘉俊92510 小时前
设计模式--享元模式:优化内存使用的轻量级设计
java·设计模式·享元模式
2301_8035545211 小时前
C++联合体(Union)详解:与结构体的区别、联系与深度解析
java·c++·算法
EnCi Zheng11 小时前
SpringBoot 配置文件完全指南-从入门到精通
java·spring boot·后端
烙印60111 小时前
Spring容器的心脏:深度解析refresh()方法(上)
java·后端·spring
为什么我不是源代码11 小时前
JPA读取数据库离谱问题-No property ‘selectClassByName‘ found-Not a managed type
java·sql
Lisonseekpan11 小时前
Guava Cache 高性能本地缓存库详解与使用案例
java·spring boot·后端·缓存·guava
我真的是大笨蛋12 小时前
Redis的String详解
java·数据库·spring boot·redis·spring·缓存
心态特好12 小时前
Jwt非对称加密的应用场景
java
七七七七0712 小时前
【Linux 系统】打开文件和文件系统
linux·运维·spring
敢敢J的憨憨L12 小时前
GPTL(General Purpose Timing Library)使用教程
java·服务器·前端·c++·轻量级计时工具库