• SpringBoot:CORS处理跨域请求的三种方式


    一、跨域背景

    1.1 何为跨域?

    Url的一般格式:

    协议 + 域名(子域名 + 主域名) + 端口号 + 资源地址

    示例:

    https://www.dustyblog.cn:8080/say/Hello 是由
    
    https + www + dustyblog.cn + 8080 + say/Hello 组成

    组成。

    只要协议,子域名,主域名,端口号这四项组成部分中有一项不同,就可以认为是不同的域,不同的域之间互相访问资源,就被称之为跨域。

    1.2 一次正常的请求

    • Controller层代码:
    1 @RequestMapping("/demo")
    2 @RestController
    3 public class CorsTestController {
    4 
    5     @GetMapping("/sayHello")
    6     public String sayHello() {
    7         return "hello world !";
    8     }
    9 }
    • 启动项目,测试请求

        浏览器打开localhost:8080/demo/sayHello

         可以打印出“hello world”

    1.3 跨域测试

    以Chrome为例:

    • 打开任意网站,如:https://blog.csdn.net

    • 按F12,打开【开发者工具】,在里面的【Console】可以直接输入js代码测试;

    var token= "LtSFVqKxvpS1nPARxS2lpUs2Q2IpGstidMrS8zMhNV3rT7RKnhLN6d2FFirkVEzVIeexgEHgI/PtnynGqjZlyGkJa4+zYIXxtDMoK/N+AB6wtsskYXereH3AR8kWErwIRvx+UOFveH3dgmdw1347SYjbL/ilGKX5xkoZCbfb1f0=,LZkg22zbNsUoHAgAUapeBn541X5OHUK7rLVNHsHWDM/BA4DCIP1f/3Bnu4GAElQU6cds/0fg9Li5cSPHe8pyhr1Ii/TNcUYxqHMf9bHyD6ugwOFTfvlmtp6RDopVrpG24RSjJbWy2kUOOjjk5uv6FUTmbrSTVoBEzAXYKZMM2m4=,R4QeD2psvrTr8tkBTjnnfUBw+YR4di+GToGjWYeR7qZk9hldUVLlZUsEEPWjtBpz+UURVmplIn5WM9Ge29ft5aS4oKDdPlIH8kWNIs9Y3r9TgH3MnSUTGrgayaNniY9Ji5wNZiZ9cE2CFzlxoyuZxOcSVfOxUw70ty0ukLVM/78=";
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'http://127.0.0.1:8080/demo/sayHello');
    xhr.setRequestHeader("x-access-token",token);
    xhr.send(null);
    xhr.onload = function(e) {
        var xhr = e.target;
        console.log(xhr.responseText);
    }

     该结果表明:该请求在https://blog.csdn.net域名下请求失败!

    二、解决方案 - Cors跨域

    2.1 Cors是什么

    CORS全称为Cross Origin Resource Sharing(跨域资源共享), 每一个页面需要返回一个名为Access-Control-Allow-Origin的http头来允许外域的站点访问,你可以仅仅暴露有限的资源和有限的外域站点访问。

     我们可以理解为:如果一个请求需要允许跨域访问,则需要在http头中设置

    Access-Control-Allow-Origin来决定需要允许哪些站点来访问。如假设需要允许https://www.dustyblog.c这个站点的请求跨域,则可以设置:
    
    Access-Control-Allow-Origin:https://www.dustyblog.cn。

    2.2 如何解决Cors跨域

       2.2.1方案一:使用@CrossOrigin注解

         在Controller上使用@CrossOrigin注解,该类下的所有接口都可以通过跨域访问

     1 @RequestMapping("/demo2")
     2 @RestController
     3 //@CrossOrigin //所有域名均可访问该类下所有接口
     4 @CrossOrigin("https://blog.csdn.net") // 只有指定域名可以访问该类下所有接口
     5 public class CorsTest2Controller {
     6 
     7     @GetMapping("/sayHello")
     8     public String sayHello() {
     9         return "hello world --- 2";
    10     }
    11 }

       这里指定当前的CorsTest2Controller中所有的方法可以处理https://csdn.net域上的请求,这里可以测试一下:

    • https://blog.csdn.net页面打开调试窗口,输入(注意:这里请求地址是/demo2,请区别于1.2 案例中的/demo)
    var token= "LtSFVqKxvpS1nPARxS2lpUs2Q2IpGstidMrS8zMhNV3rT7RKnhLN6d2FFirkVEzVIeexgEHgI/PtnynGqjZlyGkJa4+zYIXxtDMoK/N+AB6wtsskYXereH3AR8kWErwIRvx+UOFveH3dgmdw1347SYjbL/ilGKX5xkoZCbfb1f0=,LZkg22zbNsUoHAgAUapeBn541X5OHUK7rLVNHsHWDM/BA4DCIP1f/3Bnu4GAElQU6cds/0fg9Li5cSPHe8pyhr1Ii/TNcUYxqHMf9bHyD6ugwOFTfvlmtp6RDopVrpG24RSjJbWy2kUOOjjk5uv6FUTmbrSTVoBEzAXYKZMM2m4=,R4QeD2psvrTr8tkBTjnnfUBw+YR4di+GToGjWYeR7qZk9hldUVLlZUsEEPWjtBpz+UURVmplIn5WM9Ge29ft5aS4oKDdPlIH8kWNIs9Y3r9TgH3MnSUTGrgayaNniY9Ji5wNZiZ9cE2CFzlxoyuZxOcSVfOxUw70ty0ukLVM/78=";
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'http://127.0.0.1:8080/demo2/sayHello');
    xhr.setRequestHeader("x-access-token",token);
    xhr.send(null);
    xhr.onload = function(e) {
        var xhr = e.target;
        console.log(xhr.responseText);
    }

      返回结果:

    ƒ (e) {
        var xhr = e.target;
        console.log(xhr.responseText);
    }
    VM156:8 hello world --- 2

    说明跨域成功!

    • 换个域名测试一下看跨域是否还有效,在https://www.baidu.com按照上述方法测试一下,返回结果:
    OPTIONS http://127.0.0.1:8080/demo2/sayHello 403
    (anonymous)
    Access to XMLHttpRequest at 'http://127.0.0.1:8080/demo2/sayHello' 
    from origin 'http://www.cnblogs.com' has been blocked by CORS policy: 
    Response to preflight request doesn't pass access control check: 
    No 'Access-Control-Allow-Origin' header is present on the requested resource.

         说明跨域失败!证明该方案成功指定了部分域名能跨域!

      2.2.2方案二: CORS全局配置-实现WebMvcConfigurer

    • 新建跨域配置类:CorsConfig.java:
     1 /**
     2  * 跨域配置
     3  */
     4 @Configuration
     5 public class CorsConfig implements WebMvcConfigurer {
     6 
     7     @Bean
     8     public WebMvcConfigurer corsConfigurer()
     9     {
    10         return new WebMvcConfigurer() {
    11             @Override
    12             public void addCorsMappings(CorsRegistry registry) {
    13                 registry.addMapping("/**").
    14                         allowedOrigins("https://www.dustyblog.cn"). //允许跨域的域名,可以用*表示允许任何域名使用
    15                         allowedMethods("*"). //允许任何方法(post、get等)
    16                         allowedHeaders("*"). //允许任何请求头
    17                         allowCredentials(true). //带上cookie信息
    18                         exposedHeaders(HttpHeaders.SET_COOKIE).maxAge(3600L); //maxAge(3600)表明在3600秒内,不需要再发送预检验请求,可以缓存该结果
    19             }
    20         };
    21     }
    22 }
    • 测试,在允许访问的域名https://www.dustyblog.cn/控制台输入(注意,这里请求的是http://127.0.0.1:8080/demo3):
    var token= "LtSFVqKxvpS1nPARxS2lpUs2Q2IpGstidMrS8zMhNV3rT7RKnhLN6d2FFirkVEzVIeexgEHgI/PtnynGqjZlyGkJa4+zYIXxtDMoK/N+AB6wtsskYXereH3AR8kWErwIRvx+UOFveH3dgmdw1347SYjbL/ilGKX5xkoZCbfb1f0=,LZkg22zbNsUoHAgAUapeBn541X5OHUK7rLVNHsHWDM/BA4DCIP1f/3Bnu4GAElQU6cds/0fg9Li5cSPHe8pyhr1Ii/TNcUYxqHMf9bHyD6ugwOFTfvlmtp6RDopVrpG24RSjJbWy2kUOOjjk5uv6FUTmbrSTVoBEzAXYKZMM2m4=,R4QeD2psvrTr8tkBTjnnfUBw+YR4di+GToGjWYeR7qZk9hldUVLlZUsEEPWjtBpz+UURVmplIn5WM9Ge29ft5aS4oKDdPlIH8kWNIs9Y3r9TgH3MnSUTGrgayaNniY9Ji5wNZiZ9cE2CFzlxoyuZxOcSVfOxUw70ty0ukLVM/78=";
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'http://127.0.0.1:8080/demo3/sayHello');
    xhr.setRequestHeader("x-access-token",token);
    xhr.send(null);
    xhr.onload = function(e) {
        var xhr = e.target;
        console.log(xhr.responseText);
    }

      返回结果:

    ƒ (e) {
        var xhr = e.target;
        console.log(xhr.responseText);
    }
    VM433:8 hello world --- 3

     说明跨域成功,换个网址如https://www.baidu.com测试依旧出现需要跨域的错误提示,证明该配置正确,该方案测试通过。

      2.2.3方案三:拦截器Filter实现

      通过实现Fiter接口在请求中添加一些Header来解决跨域的问题

     1 @Component
     2 public class CorsFilter implements Filter {
     3 
     4     @Override
     5     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
     6             throws IOException, ServletException {
     7         HttpServletResponse res = (HttpServletResponse) response;
     8         res.addHeader("Access-Control-Allow-Credentials", "true");
     9         res.addHeader("Access-Control-Allow-Origin", "*");
    10         res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
    11         res.addHeader("Access-Control-Allow-Headers", "Content-Type,X-CAF-Authorization-Token,sessionToken,X-TOKEN");
    12         if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {
    13             response.getWriter().println("ok");
    14             return;
    15         }
    16         chain.doFilter(request, response);
    17     }
    18     @Override
    19     public void destroy() {
    20     }
    21     @Override
    22     public void init(FilterConfig filterConfig) throws ServletException {
    23     }
    24 }

     至此,跨域请求就完成了,有更多更好方法的朋友欢迎留言!

     好文转转学习自:https://www.cnblogs.com/vandusty/p/11408422.html

  • 相关阅读:
    读取XML并绑定至RadioButtonList
    获取客户端IP地址
    Repeater控件数据导出Excel
    验证用户必选CheckBox控件
    限制CheckBoxList控件只能单选
    获取客户端电脑名称
    获取Repeter的Item和ItemIndex
    获取DataList控件的主键和索引
    InsusExportToExcel Library
    ASP.NET网页打印
  • 原文地址:https://www.cnblogs.com/zhaosq/p/11410682.html
Copyright © 2020-2023  润新知