前后端之跨域请求解决

本文深入探讨了前后端分离架构下跨域请求的处理方法,包括CORS机制的原理及其在浏览器与服务器间的实现流程。介绍了如何通过配置Spring MVC拦截器来支持跨域请求,并展示了前端如何利用Vue和jQuery实现跨域请求并携带cookie。

前后端分离之跨域请求及cookie接收发送

解决思路:

使用CORS解决不同源前后端之间数据访问,和cookies-session共享(即允许前端在发送请求的时候带上本域名下的cookie访问另一个域名下的后端服务器,后端服务器允许指定域名发送cookie和接收cookie).要想实现前后端跨域,不管是在前端还是在后端都必须进行配置

什么是CORS

CORS是一个w3c标准,全称是"跨域资源共享"(Cross-origin resource sharing),但一个请求url的协议,域名,端口三者之间任意与当前页面地址不同即为跨域.它允许阅览器向跨源服务器发送XMLHttpRequest请求,从而客服AJAX只能同源使用的限制.
浏览器默认的安全限制为同源策略,即JavaScript或Cookie只能访问同源(相同协议,相同域名,相同端口)下的内容。但由于跨域访问资源需要,出现了CORS机制,这种机制让web服务器能跨站访问控制,使跨站数据传输更安全。CORS需要阅览器和服务器同时支持,目前,主流的浏览器都支持cors。

CORS的2种请求方式
  1. 简单请求
(1) 请求方法是以下三种方法之一:
        HEAD
        GET
        POST
(2)HTTP的头信息不超出以下几种字段:
        Accept
        Accept-Language
        Content-Language
        Last-Event-ID
        Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

不同时满足上面两个条件,就是非简单请求,简单请求
当进行跨域请求的时候,浏览器会自动在请求中添加Origin头部(值为:请求域名),表示这个请求是一个跨域请求
在这里插入图片描述
2. 非简单请求
不满足简单请求的条件就是非简单请求.
非简单请求相比于简单请求,需要在请求前主动请求一次Http查询请求,又称预检请求。
浏览器先请求服务器,当前网页所在域名是否在服务器许可名单中以及可以使用那些HTTP动词和头信息字段,当客户端得到肯定答复时,浏览器才会正式发出正式请求。
预检请求用的请求方法是OPTIONS,表示这个请求是用来询问的。
当服务其收到预检请求后,检查了Origin,Access-Control-Request-Method等信息字段后,如果没有问题,则确认允许跨源请求,就可以做出了回应。
在这里插入图片描述
上图为预检请求后返回的头部信息,详细说明服务器允许那些域名允许跨域,浏览器接收之后解除跨域访问限制

服务器端跨域处理流程

	1. 首先查看http头部有无origin字段;
	2. 如果没有,或者不允许,当成普通请求;
	3. 如果有且是允许的,再看是否是preflight(method=OPTIONS);
	4. 如果不是preflight(简单请求),返回Allow-Origin,Allow-Credential等字段,并返回正常内容;
	5. 如果是preflight(非简单请求),返回Allow-Headers,Allow-Methods等;
解决跨域的代码实现
1. 后端配置代码

这里使用的是springmvc拦截器,对所有服务端的响应添加头部信息

// 拦截器类
public class CrossdomainInterceptor implements HandlerInterceptor {

    // 在执行Controller方法之后执行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }
    // 在执行Controller方法前执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpServletResponse resp = (HttpServletResponse) response;
        HttpServletRequest rep = (HttpServletRequest) request;

        // 设置允许跨域的网站域名
        resp.addHeader("Access-Control-Allow-Origin", rep.getHeader("Origin"));
        // 允许跨域请求中携带cookie
        resp.addHeader("Access-Control-Allow-Credentials", "true");
        // 如果存在自定义的header参数,需要在此处添加,逗号分隔,允许跨域时带上的自定义头部
        resp.addHeader("Access-Control-Allow-Headers", "authorization,Origin, No-Cache, X-Requested-With, "
                + "If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, " + "Content-Type, X-E4M-With");
        // 允许的跨域请求方法
        resp.addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS,DELETE,PUT,");
        // 测试拦截器是否执行
        System.out.println("拦截器执行");
        return true;
    }
}

springmvc.xml 配置文件

    <mvc:interceptors>
        <!--第一个拦截器-->
        <mvc:interceptor>
            <!--要拦截的Controller方法-->
            <!--<mvc:mapping path="/**"/>表示所有方法都拦截-->
            <!--<mvc:mapping path="/users/*"/>表示只拦截users下的路径-->
            <mvc:mapping path="/**"/>

            <bean class="cn.luntan.ssm.interceptor.CrossdomainInterceptor"></bean>
            <!--表示不拦截那个地址-->
            <!-- <mvc:exclude-mapping path=""/>-->
        </mvc:interceptor>
    </mvc:interceptors>
2. 前端配置代码

前端使用vue脚手架

// 在main.js中添加如下代码,作用是允许请求时携带本域cookie和接收不同源服务器发送的cookie
axios.defaults.withCredentials=true;

jquery ajax解决跨域发送cookie

 $.ajax({
                    type: 'post',
                    url: "http://localhost:8080/post/secondcom",
                    data: JSON.stringify(data),
                    // dataType: 'jsonp',
                    
                    
                    xhrFields: {
                        withCredentials: true
                    },
                    crossDomain: true,


                    contentType: "application/json",
                    success: function (data) {
                        if (data) {
                            alert("评论成功");
                        } else {
                            alert("评论失败")
                        }
                    }
                })
将代码加入之后就可以前后端的资源访问了,快去试试吧
前后端分离架构中,请求(CORS)处理是常见的开发挑战。当浏览器发送一个带有自定义头部(如认证信息)的请求时,会先发送一个 OPTIONS 预检请求以确认服务器是否允许该请求。如果服务器返回 401 错误,则表示预检请求未通过身份验证或未正确配置响应头。 ### 常见原因分析 - **身份验证拦截**:某些后端框架(如 Spring Security、Sa-Token)在接收到 OPTIONS 请求时,仍然会执行身份验证逻辑,导致预检请求因缺少认证信息而被拒绝。 - **CORS 配置不完整**:服务器端可能未正确设置 `Access-Control-Allow-Origin`、`Access-Control-Allow-Headers` 或 `Access-Control-Allow-Methods` 等关键头部。 - **OPTIONS 请求未被放行**:部分安全框架默认不允许 OPTIONS 请求通过,需手动配置放行策略。 --- ### 解决方案 #### 1. 放行 OPTIONS 请求的身份验证 对于使用 Sa-Token 的场景,可以通过修改拦截器逻辑,确保 OPTIONS 请求不触发身份验证检查: ```java @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (request.getMethod().equals("OPTIONS")) { return true; // 放行 OPTIONS 请求 } // 其他身份验证逻辑 } ``` 此外,在全局配置中也可以添加类似的放行规则,避免 OPTIONS 请求被安全机制拦截。 #### 2. 正确配置 CORS 响应头 在 Spring Boot 中,可以使用 `@CrossOrigin` 注解或通过全局配置类实现 CORS 控制: ```java @Configuration @EnableWebMvc public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("http://localhost:5173") // 前端地址 .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .exposedHeaders("Authorization", "X-Custom-Header") // 可选 .allowCredentials(true); } } ``` 此配置确保了 OPTIONS 请求能够正常响应,并携带必要的控制头部。 #### 3. 处理 OPTIONS 请求的响应状态码 若使用 Spring Security,可在安全配置中明确允许 OPTIONS 请求通过: ```java @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.cors().and() .csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/api/**").permitAll() // 放行 OPTIONS 请求 .anyRequest().authenticated(); return http.build(); } } ``` 这样可防止 Spring Security 对 OPTIONS 请求进行不必要的身份验证,从而避免 401 错误。 --- ### 总结 解决前后端请求中 OPTIONS 返回 401 的问题,主要涉及两个方面: - 确保 OPTIONS 请求不被身份验证逻辑拦截; - 正确配置服务器响应头和 CORS 规则,使其支持请求。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值