springboot跨域解决方式

  • Post author:
  • Post category:其他


跨域指的是模块化开发时,需要处理的一个必会发生的问题,它是指前后端交互的过程中,对来自于不同源请求的一种不允许访问的问题,同源指的是协议、IP、端口三者一致。

在日常开发中,有三种方法用来处理跨域问题。


第一种:将前端代码和后端代码部署在同一个域名下。这种方法脱胎于最原始单项目开发的时候,在工作中正式开发都是多模块,所以如果你使用这种方法,就意味着你需要将后端代码和前端代码部署在tomcat里。


第二种:让后端给你添加跨域允许。

有两种方式,第一种方式是使用springboot框架封装的CORS注解解决方案,但是需要注意的是如果你的拦截器拒绝了跨域请求,那么该注解将失效,因为它生效于拦截器之后,Controller之前。

@CrossOrigin(originPatterns = "*",allowCredentials = "true")

一般情况下使用如上格式即可,该注解可以用在类上或者方法上,注解所有的属性值含义如下:


origins或者value

:支持的源,origins和value都是相同的配置,互为别名,默认配置是“*”,表示服务器支持所有源的跨域请求,安全信息较低,最好根据实际情况设置对应的信息(协议 + 域名 + 端口)。


originPatterns

:同样表示支持的源,Spring 5.3 引入的属性,默认为空,与origins二选一,支持通配符的形式配置origins,比如https://*.domain1.com,该字段为list,也就是可以配置多个。


allowedHeaders

:允许跨域的请求头信息,默认为“*”表示允许所有的请求头,CORS默认支持的请求头为:Cache-Control、Content-Language、Expires、Last-Modified、Pragma,如果你需要携带其他的请求头需要设置该属性。


exposedHeaders

:服务器允许客户端访问的相应头,默认为空,表示只允许访问:Cache-Control、Content-Language、Expires、Last-Modified、Pragma,如果需要客户端访问其他的相应头需要设置该属性。


methods

:服务器允许的Http Request类型,默认是允许GET、POST、HEAD,根据项目需要自行设置。


allowCredentials

:浏览器是否需要把凭证(如:cookies、CSRF tokens)发送到服务器,默认是关闭的,因为该选项开启后会与配置的源建立高度信任的关系,并且还会暴露一些敏感信息,所以开启该选项时origin不允许设置为“*”。


maxAge

:“预检”结果的缓存时间,单位是秒,默认1800s,在缓存时间内同一请求不需要“预检”请求。

第二种方式是使用拦截器,来处理请求头,使得请求可以跨域

package com.wy.shopapi.interceptor;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;

/**
 * 作者: wy <br/>
 * 创建时间: 2023/4/3 <br/>
 * 描述: <br/>
 * 允许跨域请求
 */
@Component
public class OriginInterceptor implements HandlerInterceptor {

    private static List<String> allowedOrigins = null;

	//allowedOrigins是一个自定义配置值
    @Value("${allowedOrigins}")
    public void setAllowedOrigins(String all) {
        OriginInterceptor.allowedOrigins = Arrays.asList(all.split(","));
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

		//获取请求的源地址
        String origin = request.getHeader("Origin");

		//允许跨域
        if (OriginInterceptor.allowedOrigins.contains(origin)) {
            response.setHeader("Access-Control-Allow-Origin", origin);
            response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
            response.setHeader("Access-Control-Allow-Headers", "Accept, Range,x-requested-with,Content-Type, Authorization");
            //response.setHeader("Access-Control-Allow-Credentials", "true");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setHeader("Access-Control-Expose-Headers", "Authorization, Accept-Ranges, Content-Encoding, Content-Length, Content-Range");
            return true;
        } else {
            return false;
        }

        /*
        如果有需要让前端携带cookie,则前端的ajax请求需要如下配置
         xhrFields:{
                withCredentials:true
          },
         crossDomain:true
         
         跨域也要设置接收cookie
         response.setHeader("Access-Control-Allow-Credentials","true");
         */
    }
}

第三种:前两种方法一个不够灵活,另一个需要设置的东西搞不好会出现网络安全问题,并且它是在代码里面的,一旦修改可能受影响的东西比较多。所以就出现了第三种方法,也是最常用的方法,就是用Nginx反向代理。前端可以通过反向代理来避免跨域问题。将前端请求发送给代理服务器,由代理服务器向后端发送请求并返回结果给前端。这样就避免了前端直接访问跨域的后端接口。



版权声明:本文为dudadudadd原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。