zl程序教程

您现在的位置是:首页 >  后端

当前栏目

跨域配置(SpringBoot、Nginx)

2023-09-27 14:24:12 时间

什么是跨域?

  简单而言,跨域请求就是当一台服务器资源从另一台服务器(不同 的域名或者端口)请求一个资源或者接口,就会发起一个跨域 HTTP 请求。举个简单的例子,从 http://www.baidu.com ,发送一个 Ajax 请求,请求地址是 http://www.taobao.com 下面的一个接口,这就是发起了一个跨域请求,在不做任何处理的情况下,显然当前跨域请求是无法被成功请求,因为浏览器基于同源策略会对跨域请求做一定的限制。

产生跨域问题的条件

例如: http://127.0.0.1:8080
当协议、IP、端口三部分中有任意一个不同时,即为跨域。

解决方案

通过设置Access-Control-Allow-Origin来实现跨域访问。

1. 使用Filter过滤器

使用Filter过滤器来过滤服务请求,向请求端设置Response Header(响应头部)的Access-Control-Allow-Origin属性声明允许跨域访问。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        // 允许跨域的源地址
        // 在Springboot2.4对应Spring5.3后在设置allowCredentials(true)的基础上不能直接使用通配符设置allowedOrigins,而是需要指定特定的URL。如果需要设置通配符,需要通过allowedOriginPatterns指定
        config.addAllowedOrigin("*");
        //config.allowedOriginPatterns("*");
        // 允许用户凭证跨域(cookie、HTTP认证及客户端SSL证明等)
        //config.setAllowCredentials(true);
        // 允许跨域的头部
        config.addAllowedHeader("*");
        // 允许跨域的方法
        config.addAllowedMethod("*");
        // 当前跨域请求最大有效时长,单位:秒
        config.setMaxAge(1800L);
        // 跨域路径配置
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

或者

import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter
public class CorsFilter implements Filter {
     @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 允许跨域的源地址
        response.setHeader("Access-Control-Allow-Origin", "*");
        // 允许跨域的头部
        response.setHeader("Access-Control-Allow-Methods", "*");
        // 允许跨域的方法
        response.setHeader("Access-Control-Allow-Headers", "*");
        // 允许用户凭证跨域(cookie、HTTP认证及客户端SSL证明等)
        response.setHeader("Access-Control-Allow-Credentials", "true");
        // 当前跨域请求最大有效时长,单位:秒
        response.setHeader("Access-Control-Max-Age", "1800");
        filterChain.doFilter(request, response);
    }
}

2. 使用FilterRegistrationBean并且设置过滤器执行顺序

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig  {
   @Bean
    public FilterRegistrationBean<CorsFilter> corsFilterRegistrationBean(){
        CorsConfiguration config = new CorsConfiguration();
        // 允许跨域的源地址
        // 在Springboot2.4对应Spring5.3后在设置allowCredentials(true)的基础上不能直接使用通配符设置allowedOrigins,而是需要指定特定的URL。如果需要设置通配符,需要通过allowedOriginPatterns指定
        config.addAllowedOrigin("*");
        //config.allowedOriginPatterns("*");
        // 允许用户凭证跨域(cookie、HTTP认证及客户端SSL证明等)
        //config.setAllowCredentials(true);
        // 允许跨域的头部
        config.addAllowedHeader("*");
        // 允许跨域的方法
        config.addAllowedMethod("*");
        // 当前跨域请求最大有效时长,单位:秒
        config.setMaxAge(1800L);
        // 跨域路径配置
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new CorsFilter(source));
        // 设置执行顺序,数字越小越先执行
        bean.setOrder(0);
        return bean;
    }
}

3. 使用 @CrossOrigin 注解

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

@RestController
@RequestMapping("/")
// @CrossOrigin
public class HelloController {
    @CrossOrigin
    @GetMapping("/hello")
    public String hello() {
        return "success";
    }

    @GetMapping("/test")
    public String test() {
        return "failure";
    }
}

4. 实现 WebMvcConfigurer,重写 addCorsMappings 方法

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistration;
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) {
        CorsRegistration cors = registry.addMapping("/**");
        // 允许跨域的源地址
        // 在Springboot2.4对应Spring5.3后在设置allowCredentials(true)的基础上不能直接使用通配符设置allowedOrigins,而是需要指定特定的URL。如果需要设置通配符,需要通过allowedOriginPatterns指定
        cors.allowedOrigins("*");
        //cors.allowedOriginPatterns("*");
        // 允许用户凭证跨域(cookie、HTTP认证及客户端SSL证明等)
        cors.allowCredentials(true);
        // 设置 header 能携带的信息
        cors.allowedHeaders("*");
        // 支持跨域的请求方法
        cors.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS");
        // 设置跨域过期时间,单位为秒
        cors.maxAge(3600);
    }
}

5. 使用Nginx配置(代理)

location / {
     #支持跨域访问
     add_header Access-Control-Allow-Origin $http_origin;
     add_header Access-Control-Allow-Credentials true;
     add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
     add_header Access-Control-Allow-Headers X-Requested-With,Authorization,Content-Type,Accept,Origin;
     add_header Access-Control-Expose-Headers Content-Length,Content-Range;
     if ($request_method = 'OPTIONS') {
         return 204;
     }
     proxy_pass http://127.0.0.1:8080/;
     proxy_redirect default;
}

跨域测试

打开浏览器并打开任意第三方网页,F12打开浏览器开发者工具,根据实际需要测试的请求地址,输入如下代码:

var x = new XMLHttpRequest();
x.open('GET','http://127.0.0.1:8080/test');
x.send(null);
x.onload = function(e) {
   var x = e.target;
   console.log(x.responseText);
}