美文网首页我爱编程
Spring Boot配置跨域访问策略

Spring Boot配置跨域访问策略

作者: 沧海一粟谦 | 来源:发表于2018-05-28 12:37 被阅读33次
    About Time

    什么是跨域

    CORS(Cross-Origin Resource Sharing)"跨域资源共享",是一个W3C标准,它允许浏览器向跨域服务器发送XMLHttpRequest请求,打破了Ajax只能访问本站内资源的同源限制,CORS在很多地方都有被使用,微信支付的JS支付就是通过JS向微信服务器发送跨域请求。

    如果在A网站中,我们希望使用Ajax来获得B网站中的特定内容,如果A网站与B网站不在同一个域中(同一协议,同一IP地址,同一端口),那么就出现了跨域访问问题,下面我们来讲一讲如何解决跨域问题。

    1.创建SpringBoot项目,预先添加Web依赖

    <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    

    2.实现WebMvcConfigurer接口

    Spring Boot 2.0中已经废弃WebMvcConfigurerAdapter类, 开发人员可以通过实现WebMvcConfigurer接口实现相应的功能

    @Configuration
    public class CORSConfiguration implements WebMvcConfigurer{
        @Override
        public void addCorsMappings(CorsRegistry registry){
            registry.addMapping("/**")
                    .allowedMethods("GET", "POST", "DELETE", "PUT","PATCH")
                    .allowedOrigins("*")
                    .allowedHeaders("*")
                    .allowCredentials(true)
                    .maxAge(3600);
        }
    }
    

    简单介绍下配置信息

    • addMapping:配置可以被跨域的路径,可以任意配置,可以具体到直接请求路径。
    • allowedMethods:允许所有的请求方法访问该跨域资源服务器,如:POST、GET、PUT、DELETE等。
    • allowedOrigins:允许所有的请求域名访问我们的跨域资源,可以固定单条或者多条内容,如:"http://www.baidu.com",只有百度可以访问我们的跨域资源。
    • allowedHeaders:允许所有的请求header访问,可以自定义设置任意请求头信息,如:"X-YAUTH-TOKEN"

    3.测试跨域请求

    创建一个测试跨域资源的控制器,这里仅仅添加了一个测试返回文本的内容,当然这个控制器可以处理任意业务逻辑。

    @RestController
    public class BaseContentler {
        @RequestMapping(value = "/req")
        public String index(){
            return "跨域访问请求成功!";
        }
    }
    

    在项目外创建一个index.html页面,页面内添加部分jquery代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>跨域资源访问</title>
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
        <script type="text/javascript">
            $(function () {
                $("#cors").click(function () {
                    $.ajax({
                        url:"http://127.0.0.1:8080/req",
                        success:function (data) {
                            alert(data);
                        }
                    })
                });
            });
        </script>
    </head>
    <body>
        <input type="button" id="cors" value="跨域资源访问"/>
    </body>
    </html>
    

    打开index.html点击按钮,界面返回/req路径的文本内容,证明我们的ajax请求通过跨域资源库访问了开放跨域的资源路径

    4.其他跨域的解决方案

    前端解决方案

    • 1.使用JSONP方式实现跨域调用;
    • 2.使用NodeJS服务器做为服务代理,前端发起请求到NodeJS服务器, NodeJS服务器代理转发请求到后端服务器;
    • 3.设置浏览器允许跨域访问,如Chrome浏览器设置--disable-web-security属性, 该方案仅适用于开发环境 下的开发调试。

    后端解决方案

    使用@CrossOrigin注解声明类和方法允许跨域访问

    @RestController
    public class BaseContentler {
        @RequestMapping(value = "/req")
        @CrossOrigin
        public String index(){
            return "跨域访问请求成功!";
        }
    }
    

    继承使用Spring Web的CorsFilter(适用于Spring MVC、Spring Boot)

    import org.springframework.stereotype.Component;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
    import org.springframework.web.filter.CorsFilter;
    import java.util.Arrays;
    
    @Component
    public class CustomCorsFilter extends CorsFilter {
    
        public CustomCorsFilter() {
            super(configurationSource());
        }
        private static UrlBasedCorsConfigurationSource configurationSource() {
            CorsConfiguration config = new CorsConfiguration();
            config.setAllowCredentials(true);
            config.addAllowedOrigin("*");
            config.addAllowedHeader("*");
            config.setMaxAge(36000L);
            config.setAllowedMethods(Arrays.asList("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"));
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/user/**", config);
            return source;
        }
    }
    

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

    @WebFilter
    public class CorsFilter implements Filter {  
        
        @Override
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {  
            HttpServletResponse response = (HttpServletResponse) res;  
            response.setHeader("Access-Control-Allow-Origin", "*");  
            response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");  
            response.setHeader("Access-Control-Max-Age", "3600");  
            response.setHeader("Access-Control-Allow-Headers", "x-requested-with");  
            chain.doFilter(req, res);  
        }  
        
        public void init(FilterConfig filterConfig) {
        }  
        
        public void destroy() {
        }  
    }
    

    Node.js如何设置允许跨域

    设置允许所有域名跨域:

    app.all("*",function(req,res,next){
        //设置允许跨域的域名,*代表允许任意域名跨域
        res.header("Access-Control-Allow-Origin","*");
        //允许的header类型
        res.header("Access-Control-Allow-Headers","content-type");
        //跨域允许的请求方式 
        res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
        if (req.method.toLowerCase() == 'options')
            res.send(200);  //让options尝试请求快速结束
        else
            next();
    }
    

    设置允许指定域名“http://www.zhangpeiyue.com”跨域:

    app.all("*",function(req,res,next){
        //设置允许跨域的域名,*代表允许任意域名跨域
        res.header("Access-Control-Allow-Origin","http://www.zhangpeiyue.com");
        //允许的header类型
        res.header("Access-Control-Allow-Headers","content-type");
        //跨域允许的请求方式 
        res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
        if (req.method.toLowerCase() == 'options')
            res.send(200);  //让options尝试请求快速结束
        else
            next();
    }
    

    设置允许多个域名跨域:

    app.all("*",function(req,res,next){
        if( req.headers.origin.toLowerCase() == "http://www.zhangpeiyue.com"
            || req.headers.origin.toLowerCase() =="http://127.0.0.1" ) {
            //设置允许跨域的域名,*代表允许任意域名跨域
            res.header("Access-Control-Allow-Origin", req.headers.origin);
        }
        //允许的header类型
        res.header("Access-Control-Allow-Headers", "content-type");
        //跨域允许的请求方式 
        res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS");
        if (req.method.toLowerCase() == 'options')
            res.send(200);  //让options尝试请求快速结束
        else
            next();    
    }
    

    如果允许的域名较多,可以将允许跨域的域名放到数组当中:

    app.all("*",function(req,res,next){
        var orginList=[
            "http://www.zhangpeiyue.com",
            "http://www.alibaba.com",
            "http://www.qq.com",
            "http://www.baidu.com"
        ]
        if(orginList.includes(req.headers.origin.toLowerCase())){
            //设置允许跨域的域名,*代表允许任意域名跨域
            res.header("Access-Control-Allow-Origin",req.headers.origin);
        }
        //允许的header类型
        res.header("Access-Control-Allow-Headers", "content-type");
        //跨域允许的请求方式
        res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS");
        if (req.method.toLowerCase() == 'options')
            res.send(200);  //让options尝试请求快速结束
        else
            next();
    }
    

    参考
    Spring Boot配置跨域访问策略
    跨域资源共享 CORS 详解

    相关文章

      网友评论

        本文标题:Spring Boot配置跨域访问策略

        本文链接:https://www.haomeiwen.com/subject/cfbwjftx.html