web应用中的跨域问题以及解决

一、什么是跨域 1、跨域的概念
同一个源下的资源与另一个源下的资源进行交换。切记 跨域仅仅是针对浏览器而言的,像两个服务端之间执行http请求的则不属于跨域。
跨域出现的场景:
1、前后端分离情况下,前台请求不同源的后台服务
2、微服务下,服务实例在多个不同源的服务上
3、资源共享,公共的静态资源如图片,音频视频等存放在一个服务中,其他web页面访问该服务获取资源(其他web页面与存放静态资源的服务不同源)
2、为什么出现跨域
浏览器的同源 : 浏览器针对 相同的协议(http、https),相同的ip,端口(port),或者域名相同的两个页面,则认为这两个页面为同源,例如 http://www.baidu.com/aaa.html 和http://www.baidu.com/bbb.html即可以被浏览器认为这两个页面为同源。而如下http://www.baidu.com/aaa.html 和http://www.58.cn/bbb.html即可以被浏览器认为这两个页面不同源。
浏览器的同源策略为:为了安全考虑,浏览器限制了同一个源加载的文档或脚本不允许与另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
二、模拟跨域

  1. 本机启动两个程序,将其端口设置为不同,则这两个应用程序即为不同源的应用程序,两个应用程序分别为127.0.0.1:7070(A应用)和127.0.0.1:7071(B应用)
A应用的前台页面为
跨域测试 - 锐客网

对应的js
//使用ajax 进行跨域请求 function test_ajax_cors(){ $.ajax({ method : 'get', url : 'http://127.0.0.1:7071/jsonp', success : function (message) { alert(message); }, async : true }) }

直接访问7071返回数据
web应用中的跨域问题以及解决
文章图片

通过应用A页面(应用A再跨域访问应用B)访问出现如下:
web应用中的跨域问题以及解决
文章图片

跨域请求常见错误 ,其实在使用ajax启动另一个同源应用的时候,请求已经到达了该应用,但是在响应到浏览器后,浏览器进行解析的时候基于同源安全策略抛出上图的错误。
三、解决方案 1、使用jsonp来解决跨域请求
使用jsonp解决跨域问题的原理:在页面上直接发起一个跨域的ajax请求是不可以的,但是,在页面上引入不同域上的js脚本却是可以的,所以我们可以在页面构造一个
应用B的服务端处理
/** *使用jsonp来实现跨域请求的操作 * 所谓的jsonp 其实就是 json(数据) padding(填充) * 填充则是由不同源的服务端进行处理,即先获取到请求的回调参数名称 * 本应用中script 访问的http://localhost:7071/jsonp?callback=showData 中的showData 为回调函数名称 * 为该回调函数填充数据参数 * @throws IOException */ @RequestMapping("/jsonp") public void jsonp(HttpServletRequest request, HttpServletResponse response,Model model) throws IOException { //获取前台提供的回调参数 //前端传过来的回调函数名称 String callback = request.getParameter("callback"); //用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了 String data = "https://www.it610.com/article/jsonp"; //给访问的页面脚本填充数据,并响应回去 String result = callback + "('"+ data +"')"; //在回调函数中填充数据,并相应给另一个应用的script response.getWriter().write(result); }

  • 使用jquery的ajax来实现跨域请求
//使用jquery的ajax来进行跨域请求 function test_ajax_jsonp(){ $.ajax({ method : 'get', url : 'http://127.0.0.1:7071/jsonp', dataType:'jsonp',//设置数据类型为jsonp类型 跨域请求的核心 jsonpCallback: "showData",//指定回调函数名称 success : function (message) { $("#text").html(message); }, async : true })

将按钮单击事件绑定该函数即可,其他保持不变
web应用中的跨域问题以及解决
文章图片

查看请求可以看到,jquery调用ajax 设置dataType:jsonp,则发起跨域请求的时候,会自动带上callback回调函数完成跨域请求操作。
jsonp缺点:只支持GET,不支持POST请求,不安全XSS,且需要服务端进行相关的数据填充操作处理。
2、postMessage:配合使用iframe
应用A
跨域测试 - 锐客网

目标iframe传来的信息:暂无信息

应用B
跨域测试 - 锐客网

暂无信息。

3、cors:需要后台配合进行相关的设置
使用CORS可以帮助我们快速实现跨域访问,只需在服务端进行授权即可,无需在前端添加额外设置,比传统的JSONP跨域更安全和便捷。
请求头信息由浏览器检测到跨域自动添加,无需过多干预,重点放在Response headers,它可以帮助我们在服务器进行跨域授权,例如允许哪些原始域可放行,是否需要携带Cookie信息等。即为用户进行跨域请求的时候,请求是可以到达不同源的服务处的,但是在进行返回的时候,如果没有设置相应的跨域请求会出现跨域请求错误
所以cors跨域请求的核心是请求不同源的响应返回的时候,设置Response headers
方式1:返回新的CorsFilter
@Configuration public class CorsConfig { //配置相应的响应消息头信息 Response Header *表示匹配所有 private CorsConfiguration buildConfig() { CorsConfiguration corsConfiguration = new CorsConfiguration(); //Access-Control-Allow-Origin //表示允许哪些原始域进行跨域访问。(字符数组) corsConfiguration.addAllowedOrigin("*"); //Access-Control-Allow-Headers //表示跨域请求的头部的允许范围。 corsConfiguration.addAllowedHeader("*"); //Access-Control-Allow-Methods //表示跨域请求的方式的允许范围。(例如只授权GET/POST) corsConfiguration.addAllowedMethod("*"); /* Access-Control-Allow-Credentials 表示是否允许客户端获取用户凭据。(布尔类型) 使用场景:例如现在从浏览器发起跨域请求,并且要附带Cookie信息给服务器。 则必须具备两个条件:1. 浏览器端:发送AJAX请求前需设置通信对象XHR的withCredentials 属性为true。 2.服务器端:设置Access-Control-Allow-Credentials为true。 两个条件缺一不可,否则即使服务器同意发送Cookie,浏览器也无法获取。 */ corsConfiguration.setAllowCredentials(true); /* Access-Control-Expose-Headers 表示暴露哪些头部信息,并提供给客户端。 (因为基于安全考虑,如果没有设置额外的暴露, 跨域的通信对象XMLHttpRequest只能获取标准的头部信息) Access-Control-Max-Age 表示预检请求 [Preflight Request] 的最大缓存时间。 */ return corsConfiguration; }@Bean public CorsFilter corsFilter() { //url 路径映射 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", buildConfig()); return new CorsFilter(source); } }

方式2:重写WebMvcConfigurer
public class MyWebMvcConfigurer implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { //添加映射路径 registry.addMapping("/**") //放行哪些原始域 .allowedOrigins("*") //是否发送Cookie信息 .allowCredentials(true) //放行哪些原始域(请求方式) .allowedMethods("GET","POST", "PUT", "DELETE") //放行哪些原始域(头部信息) .allowedHeaders("*"); //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息) //.exposedHeaders("Header1", "Header2"); } }

方式3:使用注解(@CrossOrigin)
@RequestMapping("/cors") @CrossOrigin(origins = "http://127.0.0.1:7070",allowCredentials = "true") public String corsLogin(String message,Model model) { model.addAttribute("messgae",message); return "postMessage"; }

方式4:手工设置响应头(HttpServletResponse )
cors配置参考:http://www.spring4all.com/article/177
上面配置结束后,就可以使用正常的ajax进行处理,而不用考虑前端进行处理复杂跨域请求。
4、document.domain:仅限于同一域名下的子域
5、websocket:需要后台配合修改协议,不兼容
6、proxy:使用代理去避开跨域请求,需要修改nginx、apache等的配置


【web应用中的跨域问题以及解决】至此,有关跨域问题的探讨到此结束,有什么不正确的还望不吝赐教,手写不易,帮到你的话,希望您点个赞。

    推荐阅读