关于跨域问题的理解

Posted by codegirl on March 20, 2021

关于跨域问题,网上的解释说明很多,比如:关于跨域,你想知道的全在这里 。纸上得来终觉浅,绝知此事要躬行,看的似懂非懂,所以这里结合自己遇到的问题场景,进行说明记录,加深理解。

1、问题场景和调试

在前端测试过程中,如下图所示登陆界面,点击 “登陆”按钮的时候,调用axios post请求,将用户填写的用户名、密码信息,发送给后端进行校验。

图1

浏览器控制台提示错误 Access to XMLHttpRequest at '*' from origin '*' 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. 结合应用场景,就是前端http://192.168.31.190:8080向后端http://192.168.31.151:9090/api/v1/login请求数据的时候失败了。经查询,这就是传说中的“跨域“问题了!!!

既然发生错误,先看看问题出现在哪里,请求有没有成功发送?后端接口有没有接收到请求返回数据?为此,进行了一下测试,在不修改任何代码的情况下,在后端接口断点调试,前端再次发送请求,看后端能否接收到请求。测试结果发现,后端接口是可以收到请求且正常返回,如下图所示。

图2

浏览器端切换到Network,看到的结果如下图所示,Failed to load response data。说明,请求已经发送出去了,后端也已经接收到请求并返回结果了,只是response数据没有被浏览器加载。这基本上就弄清楚了问题出现的点是在于浏览器。

图3

那么关于浏览器为什么会这么做,简单来说就是浏览器同源政策,关于这部分,网上有很多大佬做了详细说明和举例,此处就不再赘述,具体可以查看浏览器同源政策及其规避方法

2、问题解决方法

下面就来说说有什么解决方法。关于解决方法,前端常见跨域解决方案(全)10 种跨域解决方案(附终极方案)这些文章也给出了足够多和专业的方法。我在这里也只想说,从我的理解上看,跨域问题的解决可以从前端解决也可以从后端解决。

(1)后端解决

后端解决跨域问题,从实现上看就比较简单,例如我使用的springboot搭建后端,此时仅需要在Controller类上添加一个“@CrossOrigin“注解就可以实现对当前Controller 的跨域访问了,代码如下所示。

@Api(value = "LoginController", tags = "登录界面")
@RestController
@RequestMapping("/api/v1")
@CrossOrigin
@Slf4j
public class LoginController {
    @Autowired
    private UserInfoMapper userInfoMapper;

    @PostMapping("/login")
    public CommonResult checkUserInfo(@RequestBody UserInfo userInfo){
        List<UserInfo> userInfos = userInfoMapper.selectByUserNameAndPassword(userInfo.getUserName(), userInfo.getPassword());
        if(userInfos!=null && userInfos.size()>0){
            return CommonResult.success("登录成功");
        }
        return CommonResult.failed("用户不存在");
    }

}

此时,再次点击界面登陆,浏览器网络请求和响应如下所示,浏览器成功加载response数据。

图4

图5

采用后端解决方式,Request URL为http://192.168.31.151:9090/api/v1/login,即请求后端真实的IP和端口(192.168.31.151:9090为后端的IP和端口),解决方式是通过在Response Headers中设置了Access-Control-Allow-Origin 属性。其请求/响应流程如下图所示。

后端

(2)前端解决

前端解决跨域问题,稍显麻烦一点,例如我是用Vue脚手架搭建的前端工程,可以通过设置vue.config.js配置文件,具体如下。

module.exports = {
    dev: {
        // Paths
        assetsSubDirectory: 'static',
        assetsPublicPath: '/',
        proxyTable: {
            '/api': {
                target: 'https://192.168.31.151:9090', // 后端服务器地址
                changeOrigin: true, // 是否跨域
                pathRewrite: { 、// 转发
                    '^/api': '/api'
                },
                secure: false 
            },
        }
}

此时,再次点击界面登陆,和后端解决跨域问题一样,浏览器成功加载response数据。

图6

采用前端代理配置方式解决Request URL为http://192.168.31.190:8080/api/v1/login(192.168.31.190:8080为前端的IP和端口),此时协议、域名、端口均相同,属于同源,跨域问题解决,其请求/响应流程如下图所示。

前端解决