分享程序网
首页
  • java
微服务
微前端
环境搭建
数据库
设计模式
算法
软件
解决问题
链接
首页
  • java
微服务
微前端
环境搭建
数据库
设计模式
算法
软件
解决问题
链接
  • 问题解决

    • 跨域问题

跨域问题

代理方式

​ 可以使用代理方式解决跨域问题,例如Nginx,或者VUE和REACT使用http-proxy-middleware

React:

const proxy = require("http-proxy-middleware");
 
module.exports = function(app) {
  app.use(
    proxy("/api/**", {
      target: "http://127.0.0.1:8080",//跨域地址
      changeOrigin: true
    })
  );
};

Vue:

const proxy = require('http-proxy-middleware');

module.exports = {   
devServer:{
    host: 'localhost',//target host
    port: 8080,
    //proxy:{'/api':{}},代理器中设置/api,项目中请求路径为/api的替换为target
    proxy:{
        '/api':{
            target: 'http://127.0.0.1:8080',//代理地址,这里设置的地址会代替axios中设置的baseURL
            changeOrigin: true,// 如果接口跨域,需要进行这个参数配置
            //ws: true, // proxy websockets
            //pathRewrite方法重写url
            pathRewrite: {
                '^/api': '/' 
                //pathRewrite: {'^/api': '/'} 重写之后url为 http://http://127.0.0.1:8080/xxxx
                //pathRewrite: {'^/api': '/api'} 重写之后url为 http://http://127.0.0.1:8080/api/xxxx
           }
    }}
},
//...
}

跨域方式

​ 一般有些工具可以支持跨域请求,必须使用后台进行配置,运行跨域的请求,例如jsonp,axios;例如使用

为例:

	function getList() {
        axios.get('/api/getUser', {
            params: {
                username: 'zahngsan',
                currentPage: 1,
                pageCount: 50
            },
            baseURL: 'http://127.0.0.1:8080',
            headers: {
                'Authorization': 'bearer xxxxxxxxxxx'
            },
            // proxy: {
            //     host: '10.176.125.92',
            //     port: 8081
            // },
            // withCredentials: true
        }).then(function (rs) {
            console.log(rs)
        }).catch(function (e) {
            console.log(e)
        });
    }

这时候后台有几种较为常见的配置方式:

Controller层添加注解:

使用@CorssOrigin 注解需要引入 Spring Web 的依赖,该注解可以作用于方法或者类,可以针对这个方法或类对应的一个或多个 API 配置 CORS 规则:

@RestController
@CrossOrigin
class UserController {
    
    @GetMapping("/getUSer")
    public String getUSer(String username) {
        return username;
    }
}

可以加在类上面,那么类下面所有的方法都支持跨域请求,如果加在方法上,仅当前方法支持。

实现 WebMvcConfigurer.addCorsMappings 方法

WebMvcConfigurer 是一个接口,它同样来自于 Spring Web。我们可以通过实现它的 addCorsMappings 方法来针对全局 API 配置 CORS 规则:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
     /**
     * 跨域支持
     */
     @Override
     public void addCorsMappings(CorsRegistry registry) {
         registry.addMapping("/**")
         .allowedOrigins("*")
         .allowedHeaders("*")
         .allowCredentials(true)
         .allowedMethods("*")
         .maxAge(3600 * 24);
     }
}

或者bean注入

	@Bean
	public WebMvcConfigurer corsConfigurer() {
		return new WebMvcConfigurerAdapter() {
			@Override
			public void addCorsMappings(CorsRegistry registry) {
				registry.addMapping("/**")
						.allowedOrigins("*")
						.allowedMethods("*")
						.allowedHeaders("*")
						.allowCredentials(true)
                    	.maxAge(3600 * 24);
			}
		};
	}

注入 CorsFilter

CorsFilter 同样来自于 Spring Web,但是实现 WebMvcConfigurer.addCorsMappings 方法并不会使用到这个类,具体原因我们后面来分析。我们可以通过注入一个 CorsFilter 来使用它:

@WebFilter("/getUser")
public class CorsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse)servletResponse;
        //设置允许跨域访问的服务域名,*号表示允许所有域访问
        //resp.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Origin", "*");
        //设置允许跨域的请求方法
        response.setHeader("Access-Control-Allow-Methods", "*");
        //放行
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

或者bean注入

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

这种方式较多,可以自行百度

Spring Security 中的配置

注入bean

	@Bean
	public CorsConfigurationSource corsConfigurationSource() {
		final CorsConfiguration configuration = new CorsConfiguration();
		// 预检请求的有效期,单位为秒
		configuration.setMaxAge(3600L);
		//允许跨域访问的域名
		configuration.setAllowedOrigins(Collections.singletonList("*"));
		//允许的请求方法
		configuration.setAllowedMethods(Collections.singletonList("*"));
		// 是否支持安全证书
		configuration.setAllowCredentials(true);
		//允许的请求头
		configuration.setAllowedHeaders(Collections.singletonList("*"));
		final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
		source.registerCorsConfiguration("/**", configuration);
		return source;
	}

在ResourceServerConfigurerAdapter实现类中配置

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Autowired
    private CorsConfigurationSource corsConfigurationSource;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().exceptionHandling()
                .authenticationEntryPoint(
                        (request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
                .and().requestMatchers().antMatchers("/**")
                .and().authorizeRequests()
                .antMatchers("/user/login", "/user/logout").permitAll()
//                .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
                .anyRequest().authenticated() //等同于 .antMatchers("/**").authenticated()
                .and()
                .httpBasic()
                .and()
                .cors().configurationSource(corsConfigurationSource)
        ;
    }

}
Last Updated:
Contributors: chengli