• 前后端分离需要处理的跨域解决方案


    环境

    前端

    vue + axios

    后端

    springboot

    问题与方案

    这里可以看文献的《跨域资源共享》;请求分为简单请求复杂请求简单请求直接进行正式请求,而复杂请求则会在正式请求之前发送请求方式为OPTIONS的预检请求。

    跨域解决方案(针对复杂请求)

    第一种

    原因: 缺少跨域的Header标头

    解决:

        // 实现 implements WebMvcConfigurer 接口
    	@Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
                    .allowCredentials(true)
                    .allowedOrigins("http://localhost:8080")
                    .allowedMethods("GET","POST","DELETE","PUT","OPTIONS")
                    .allowedHeaders("*");
                    // .exposedHeaders("Allow"); //这一句可以不需要,暴露指定的header
        }
    

    第二种

    原因: (OPTIONS)预检请求返回的不是OK的状态码(200)

    解决: 解决后台的报错问题即可

    第三种

    由于我是集成了SpringSecurity,那么只需添加以下代码片段即可

        /**
         * 注入CORS配置源
         * @see WebMvcConfiguration#addCorsMappings(org.springframework.web.servlet.config.annotation.CorsRegistry)
         */
        @Resource
        private CorsConfigurationSource corsConfigurationSource;
    
    protected void configure(HttpSecurity http) throws Exception
       http.cors().configurationSource(corsConfigurationSource)
    }
    

    如果没有集成SpringSecurity,那么添加以下代码(未测试)

        /**
         * 注入CORS配置源
         * @see WebMvcConfiguration#addCorsMappings(org.springframework.web.servlet.config.annotation.CorsRegistry)
         */
        @Resource
        private CorsConfigurationSource corsConfigurationSource;
    
    
    @Bean
        public FilterRegistrationBean<CorsFilter> corsFilterFilterRegistrationBean(){
            FilterRegistrationBean<CorsFilter> corsFilterFilterRegistrationBean = new FilterRegistrationBean<>();
            corsFilterFilterRegistrationBean.setUrlPatterns(Collections.singleton("/*"));
            corsFilterFilterRegistrationBean.setOrder(0); // 这里调整的执行次序,按自己所需的值修改
            corsFilterFilterRegistrationBean.setFilter(new CorsFilter(configSource));
            corsFilterFilterRegistrationBean.setEnabled(true);
            return corsFilterFilterRegistrationBean;
        }
    

    第四种:忽略OPTIONS预检请求

    //注册一个 Filter 过滤器,对OPTIONS请求直接返回即可
    if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
                response.addHeader("Allow", ""); //这个Allow有大用
                return false;
    }
    
    /**
     * Security的自定义认证过滤器实现,此为参考即可;只列出了主要代码以供参考
    */
    public class JwtAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    
        /**
         * 此方法返回是否需要认证
         * @param request
         * @param response
         * @return
         */
        @Override
        protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
            if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
                response.addHeader("Allow", "");
                return false;
            }
            return super.requiresAuthentication(request, response);
        }
        ...
    }
    
    /**
      只列出了主要代码以供参考;可以在doFilter方法里过滤OPTIONS预检请求
    */
    public class JwtOnceAuthenctionFilter extends OncePerRequestFilter {
    
        /**
        	此方法的返回值只决定了执行不执行当前过滤器而已,这里只是位置,并未加代码,可参考上方忽略
        	预检请求(OPTIONS)的片段
        */
        @Override
        protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
            return super.shouldNotFilter(request);
        }
        ...
    }
    

    response.addHeader("Allow", ""); 这里说下这句代码的用意,主要就是终结这个请求的执行而已

    /**
    留下代码定位,Debug看吧
    
    org.springframework.web.servlet.FrameworkServlet#doOptions
    
    */	
    
    @Override
    	protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    		if (this.dispatchOptionsRequest || CorsUtils.isPreFlightRequest(request)) 		{
    			processRequest(request, response);
                //这里会判断响应Header是否包含`Allow`,值目前并没有找到需要的地方
    			if (response.containsHeader("Allow")) {
    				// 来自处理程序的正确OPTIONS响应-我们完成了。
    				return; //这个请求就这样执行完了
    			}
    		}
            ......................
     }
    
    

    相关文献

    复制请注明出处,在世界中挣扎的灰太狼
  • 相关阅读:
    十二、React 生命周期函数
    十一、React 获取服务器数据: axios插件、 fetch-jsonp插件的使用
    备份CSDN
    十、React 父组件传来值的类型控制propTypes、父组件如果不传值defaultProps
    九、React中的组件、父子组件、React props父组件给子组件传值、子组件给父组件传值、父组件中通过refs获取子组件属性和方法
    phpStudy配置多站点多域名和多端口的方法
    八、8.2自写模块,引入及使用(封装)
    八、React实战:可交互待办事务表(表单使用、数据的本地缓存local srtorage、生命同期函数(页面加载就会执行函数名固定为componentDidMount()))
    七、React表单详解 约束性和非约束性组件 input text checkbox radio select textarea 以及获取表单的内容
    索引原理与数据库优化
  • 原文地址:https://www.cnblogs.com/XingXiaoMeng/p/14100563.html
Copyright © 2020-2023  润新知