SpringBoot解决浏览器跨域问题的三种方案

一、前言(随便聊聊)

  晚风中,奔跑在田间小路的那个少年,仿佛就在昨天。

  对于Web开发而言,前后端一把梭的时代早已渐行渐远。像我这非科班出身的半吊子程序员,对于JSP仅仅只是知道一个概念(当然严格来讲JSP不是前端,是运行于服务端的页面,前端特指浏览器端)。

  自从参加工作至今,接手的几个项目都是采用前后端分离的架构进行开发,这是大环境下的趋势。我始终认为思想和技术的进步让工作更加便利,也对从业人员提出了更高的要求,使得IT人分化严重,上限要求越来越高,下限要求也变得越来越低。

  人生苦短,我们的目标永远不要做一个API调用工程师。

二、何为跨域?

1.概念

简单来说,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制。

2.构成跨域的条件

同源策略:是指协议域名端口都要相同,其中有一个不同都会产生跨域;
举个例子:http://www.baidu.com:8888

  • http:协议
  • www.baidu.com:域名(进一步分:子域名、主域名)
  • 8888:端口号

三、测试项目和HTML页面(创造跨域条件)准备

1.后端

  准备一个SpringBoot项目,这就是我们的测试基础。由于准备项目不是本文重点,对于如何创建项目相信大家都已经掌握。最终的项目结构截图:
在这里插入图片描述
  简单测试一下吧,浏览器地址栏输入URL:http://localhost:8080/hello
在这里插入图片描述

2. 前端

  为了方便,我直接通过国内CDN引入了axios,使用axios发送请求,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>跨域测试</title>
  <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>
</head>
<body>
  <script>
    axios.get('http://localhost:8080/hello')
    .then(response=>{
      console.log(response);
    })
  </script>
</body>
</html>

  使用浏览器打开上述html文件,按F12,查看Console。结果:
在这里插入图片描述
  很明显,跨域了。下面我们就来探讨如何解决跨域问题。

四、解决跨域问题的三种方案

1.方案一:借助注解@CrossOrigin

  @CrossOrigin注解作用于Controller类上,它的作用范围是当前Controller,能够解决当前Controller中请求的跨域问题。代码如下:

package com.ieslab.corsdemo.controller;

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

/**
 * @version V1.0
 * @Title:
 * @Package com.ieslab.corsdemo.controller
 * @Description: TODO
 * @author: zongshaofeng
 * @date 2021/5/23
 */
@RestController
@CrossOrigin
public class HelloWorldController {
    @RequestMapping("/hello")
    public String sayHello(){
        return "Hello SpringBoot!";
    }
}

  此时,重新启动SpringBoot项目,我们再次F5刷新我们的测试页面,从F12中查看结果。
在这里插入图片描述
在这里插入图片描述
  可以发现,跨域问题得到了解决。刚才说@CrossOrigin只能管当前Controller类,那我们再加一个HelloWorld2Controller类试一下,看看效果,前后端都修改一下代码,如下:
在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>跨域测试</title>
  <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>
</head>
<body>
  <script>
    axios.get('http://localhost:8080/hello')
    .then(response=>{
      console.log(response);
    })

    axios.get('http://localhost:8080/hello2')
    .then(response=>{
      console.log(response);
    })
  </script>
</body>
</html>

  重新运行结果如下:
在这里插入图片描述
  发现,新增加的请求跨域了,那就证明了我们上述的结论,@CrossOrigin只能作用于当前COntroller类。

那我们怎么进行全局设置呢?继续来看。

2.方案二:CORS全局配置之实现WebMvcConfigurer

  WebMvcConfigurer这个接口的功能非常丰富,丰富到完全可以单独开一篇博客来详细的谈论一下,可以通过WebMvcConfigurer实现额外的MVC配置,不仅仅解决跨域问题,还有比如拦截器配置等。

  去掉@CrossOrigin注解,新增一个config/CorsConfig配置类,目录和代码如下:
在这里插入图片描述

package com.ieslab.corsdemo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @version V1.0
 * @Title:跨域配置类
 * @Package com.ieslab.corsdemo.config
 * @Description: TODO
 * @author: zongshaofeng
 * @date 2021/5/23
 */
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").
                allowedOriginPatterns("*"). //允许跨域的域名,可以用*表示允许任何域名使用
                allowedMethods("*"). //允许任何方法(post、get等)
                allowedHeaders("*"). //允许任何请求头
                allowCredentials(true). //带上cookie信息
                //maxAge(3600)表明在3600秒内,不需要再发送预检验请求,可以缓存该结果
                exposedHeaders(HttpHeaders.SET_COOKIE).maxAge(3600L);
    }
}

  此时,让我们重新刷新页面,看结果:
在这里插入图片描述
在这里插入图片描述
  这波怎么说?完美解决。

3.方案三:CORS全局配置之过滤器(Filter)实现

  通过实现Fiter接口在请求中添加一些Header来解决跨域的问题。
  移除方案二的跨域配置类,然后增加filter/CorsFilter过滤器,目录结构和代码如下所示:
在这里插入图片描述

package com.ieslab.corsdemo.filter;

import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @version V1.0
 * @Title:
 * @Package com.ieslab.corsdemo.filter
 * @Description: TODO
 * @author: zongshaofeng
 * @date 2021/5/23
 */
@Component
public class CorsFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //TODO
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse res = (HttpServletResponse) response;
        res.addHeader("Access-Control-Allow-Credentials", "true");
        res.addHeader("Access-Control-Allow-Origin", "*");
        res.addHeader("Access-Control-Allow-Methods", "*");
        res.addHeader("Access-Control-Allow-Headers", "Content-Type,X-CAF-Authorization-Token,sessionToken,X-TOKEN");
        if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {
            response.getWriter().println("ok");
            return;
        }
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        //TODO
    }
}


  刷新页面,查看结果:
在这里插入图片描述
  同样可以完备解决跨域问题。

五、后话

  行文至此,SpringBoot解决前后端分离项目中浏览器跨域问题的探讨,基本就告一段落了,由于篇幅和精力有限,其中的原理分析就不在这里一一展开了,感兴趣的可以继续深入学习。

  这个周末一口气写了三篇博客,按照最初给自己定的一月一篇的目标,最起码不至于断更了,有些坚持没有意义,但什么又是有意义的呢?
  小宗,于2021年5月23日16:09:53,济南。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是小宗啊?

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值