跨域问题的原因及解决方案

0、心是冰冰的

王冰冰0001

1、首先要知道什么是跨域?

跨域它是浏览器的一种同源策略限制,同源策略的又是一种浏览器约定,也是浏览器最核心的安全功能,缺少同源策略,浏览器以及网站很容易受到各种攻击,如常见的XSS、CSFR等攻击。

2、那为什么会出现跨域呢?

我们都知道要想访问一个网站,首先要知道这个网站的URL,才能够进入该网站。而URL是由协议、域名、端口组成的(协议,浏览器自动填充;域名的端口默认为80,所以通常这两项不用输入)。而跨域就是说去访问的网站信息中的协议、域名、端口号这三者之中任意一个与当前页面的URL地址不同就是跨域。即使两个不同的域名指向同一个ip地址,也是跨域(即非同源)。

举个栗子:
一个钓鱼网站的页面通过iframe嵌入了某宝的登录页面,如果没有同源限制,钓鱼网站上的js脚本就可以获取到用户账号和密码。也就是说,同源限制策略就是限制了一下几种行为:
Cookie、LocalStorage(浏览器缓存)和IndexDb(浏览器数据库)
DOM和JS对象无法操作
Ajax无法发送请求
同源策略并不会限制HTML标签,只会限制js的读写加载权限。
既然了解了出现问题的原因,我们再来说说解决方案,针对跨域的解决方案主要有三种方式,

  1. 后端代码实现
  2. Nginx配置
  3. 前端代码实现

但是大部分都是在后端代码中实现的,所以重点介绍第一种。

3、后端代码解决跨域问题方案:

后端实现中又主要分为5种方式,这种5方式都是各有千秋,具体选择哪种方式还需要具体看业务场景。

  • 返回CorsFilter
  • 重写WebMvcConfiguration
  • 使用@CrossOrigin注解
  • 设置HttpServletResponse响应头
  • 自定义Web filter过滤器

【说明】:
返回CorsFilter和重写WebMvcConfiguration的方式是针对解决跨域问题的全局配置,@CrossOrigin注解是针对某一个类或某一个接口来设置的,主要是来进行细颗粒度更高的解决方案,设置HttpServletResponse和自定义web filter过滤器是属于局部配置
其中前三种方式是针对SpringBoot 1.3版本以上或SpringMVC 4.2版本以上才行。
不管是哪种方式,最终的目的都是来修改响应头来做到协议域名和端口一致。

设置返回CorsFilter方式

我们以SpringBoot来举例,我们需要写一个配置类,返回一个新的CorsFilter Bean,其中主要设置两种信息,一个就是设置CORS配置信息,另外一个就是添加CORS映射路径

@Configuration
public class GlobalCorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        // 1. 添加 CORS配置信息
        CorsConfiguration config = new CorsConfiguration();
        // 允许跨域访问的域名,可填写具体域名,*代表允许所有访问
        config.addAllowedOrigin("*");
        // 是否允许携带cookie
        config.setAllowCredentials(true);
        // 允许访问类型:get  post 等,*代表所有类型
        config.addAllowedMethod("*");
        //放行哪些原始请求头部信息
        config.addAllowedHeader("*");
        //暴露哪些头部信息
        config.addExposedHeader("*");
        // 2. 添加映射路径
        UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
        corsConfigurationSource.registerCorsConfiguration("/**",config);
        // 3. 返回新的CorsFilter
        return new CorsFilter(corsConfigurationSource);
    }
}

【注意】:
其中像上面的设置跨域访问的域名设置的是“”,代表就是允许所有域名访问。但是真实的项目环境中是不允许这么干的,(主要是会安全性降低),应该设置具体的域名;以及访问类型都是要设置具体的访问方式,多个访问类型逗号隔开。下面的几种方式同上。*

重写WebMvcConfiguration方式

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowCredentials(true)
                .allowedOrigins("*")
                .allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
                .allowedHeaders("*")
                .exposedHeaders("*");
    }
}

使用@CrossOrigin注解

它可以放到Collection类上,表示该类所有的接口都允许跨域。

@RestController
@CrossOrigin(origins = "*")
public class HelloController {

    @RequestMapping("/hello")
    public String hello() {
        return "hello world";
    }
    
}

也可以具体到某一个接口上

@RestController
public class HelloController {

    @CrossOrigin(origins = "*")
	// @CrossOrigin(value = "http://localhost:8081") // 指定具体ip允许跨域
	public String hello() {
	    return "hello world";
	}
	
}

设置HttpServletResponse响应头

使用 HttpServletResponse 对象添加响应头(Access-Control-Allow-Origin)来授权原始域。

@RequestMapping("/index")
public String index(HttpServletResponse response) {

    response.addHeader("Access-Allow-Control-Origin","*");
    return "index";
    
}

自定义Filter过滤器实现跨域

@Component
public class MyCorsFilter implements Filter {
	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,content-type");
		chain.doFilter(req, res);
	}
	public void init(FilterConfig filterConfig) {}
	public void destroy() {}
}

然后需要在web.xml中配置这个过滤器,使其生效。

<!-- 跨域访问 START-->
<filter>
 <filter-name>CorsFilter</filter-name>
 <filter-class>com.mesnac.aop.MyCorsFilter</filter-class>
</filter>
<filter-mapping>
 <filter-name>CorsFilter</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 跨域访问 END  -->

4、Nginx配置和前端处理的方式解决跨域

我们再来说一下使用Nginx和前端处理的方式来如何解决跨域的。
Nginx只需要在配置文件中做配置即可:

在这里插入图片描述
前端的解决方案是在Ajax是用设置请求方式为jsonp。

$.ajax({
    url: 'http://www.domain2.com:8080/login',
    type: 'get',
    dataType: 'jsonp', // 请求方式为jsonp
    jsonpCallback: "onBack", // 自定义回调函数名
    data: {}
});

但是这种做法并非官方推荐方式,而且JSONP只支持GET请求。JSONP的原理就是通过动态添加<script>标签来调用服务器的脚本(标签含有src属性,标签是没有跨域限制的,同理src属性也是没有跨域限制),而Ajax请求是通过XHR(XmlHttpRequest)对象来请求的。

前端常见跨域解决方案可以参考这篇博客:前端常见跨域解决方案(全)

其中这两种方式使用率普遍不高,了解即可。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值