Spring Cloud 前后端分离后引起的跨域访问解决方案
背景
Spring Cloud 微服务试点改造,目前在尝试前后端分离。
前台A应用(本机8080端口),通过网管(本机8769端口)调用后台应用B(本机8082端口)、应用C发布的http服务。。

A的js代码如下:
$.ajax({
type: "POST",
async: "true",
url: "http://127.0.0.1:8769/service-B/getResInfo",
data:{resTypeId:201}
dataType:"json",
xhrFields: {
withCredentials: true
},
error: function (XMLHttpRequest, textStatus, errorThrown) { alert(textStatus + "," + errorThrown); }, beforeSend: function (XMLHttpRequest) { }, success: function (data) { ... } });
运行后报错:
XMLHttpRequest cannot load http://127.0.0.1:8769/service-B/getResInfo. No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:8080' is therefore not allowed access.
问题原因
A的前台访问B应用,导致了跨域。
跨域访问违反了同源策略,同源策略规定:浏览器的ajax只能访问跟它的前台页面同源(相同域名或IP)的资源。
也就是说,如果A的前台访问A的后台,则不会跨域。。
解决方案
尝试了两种解决办法,最终采用了方案二。。
方案一:
在被调用的类或方法上增加@CrossOrigin注解来声明自己支持跨域访问
origins=*表示允许所有来源都支持,也可以定义特定的来源,比如http://domain1.com
allowCredentials=true 表示response里会增加标示Access-Control-Allow-Credentials=true
@RequestMapping(value="/getResInfo",method = {RequestMethod.POST})
@CrossOrigin(allowCredentials="true", allowedHeaders="*", methods={RequestMethod.POST}, origins="*")
public List<Map<String,Object>> getResInfo(@RequestParam(name = "resTypeId", required = false) String resTypeId){
。。。
}
如果只是针对某个服务需要被跨域访问,用此方案可行。。
但由于我们进行了前后端分离,前台调用的都是跨域的服务,此方案需要对几乎所有的B、C应用的服务对应的方法或者类上增加注解,不太合适。
而且,如果B、C服务都开放了跨域访问,则可能存在安全隐患,因为其他未知应用也可以访问这些服务。。
方案二:
在网管zuul里增加CorsFilter过滤器,比如下图直接在启动类里增加红色部分代码
@SpringBootApplication
@EnableZuulProxy
public class DemoZuulApplication { public static void main(String[] args) {
SpringApplication.run(DemoZuulApplication.class, args);
} @Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true); // 允许cookies跨域
config.addAllowedOrigin("*");// 允许向该服务器提交请求的URI,*表示全部允许。。这里尽量限制来源域,比如http://xxxx:8080 ,以降低安全风险。。
config.addAllowedHeader("*");// 允许访问的头信息,*表示全部
config.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
config.addAllowedMethod("*");// 允许提交请求的方法,*表示全部允许,也可以单独设置GET、PUT等
/* config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");// 允许Get的请求方法
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");*/
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
} }
后来zuul上又增加了其他的过滤器,而此跨域过滤器必须在其他过滤器之前,所以写法改成如下的方式,即借助FilterRegistrationBean将此过滤器的order设置为0,即最先加载的过滤器。。order值越大加载越晚。。
@Bean
public FilterRegistrationBean corsFilter() { final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true); // 允许cookies跨域
config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
config.addAllowedHeader("*");// #允许访问的头信息,*表示全部
config.setMaxAge(1800L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
config.addAllowedMethod("*");// 允许提交请求的方法,*表示全部允许
/* config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");// 允许Get的请求方法
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");*/
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new org.springframework.web.filter.CorsFilter(source));
bean.setOrder(0);
return bean;
}
由于此方案是增加到网管上的,对B、C应用的代码都无任何改造。。
且因为B、C未直接开放跨域访问,所以其他应用无法跨越访问B、C服务,比如A不经过网关直接访问B、C应用会访问失败。。
后续会对网管应用装配上SSO进行单点登录校验,来更好的保障服务安全。。
'Access-Control-Allow-Origin' header contains multiple values的报错的解决方案
今天遇到一个跨域的报错:f12谷歌浏览器发现:
Failed to load http://127.0.0.1:8769/device-service/routeService/queryViewPathString: The 'Access-Control-Allow-Origin' header contains multiple values 'http://127.0.0.1:8080, http://127.0.0.1:8080', but only one is allowed. Origin 'http://127.0.0.1:8080' is therefore not allowed access.
这个问题是因为重复配置了跨域过滤器。。比如zuul里已经配置了CorsConfiguration,在业务应用里又配置了一次CorsConfiguration。。则会出现此问题。。
解决方案:去掉业务应用里的配置,统一在网关进行配置即可。
前端ajax跨域访问后端时,如果需要cookie一并发送,则需要做增加withCredentials参数。。否则会引起后台获取的session每次都变化的问题。
xhrFields: {
withCredentials: true
},
本文参考:http://blog.csdn.net/liuchuanhong1/article/details/62237705
Spring Cloud 前后端分离后引起的跨域访问解决方案的更多相关文章
- 解决前后端分离后的Cookie跨域问题
一. 前端Ajax关键配置 $.ajax({ type: "post", url: xxx, data: xxx, contentType: 'application/json', ...
- vue+springboot前后端分离实现单点登录跨域问题处理
最近在做一个后台管理系统,前端是用时下火热的vue.js,后台是基于springboot的.因为后台系统没有登录功能,但是公司要求统一登录,登录认证统一使用.net项目组的认证系统.那就意味着做单点登 ...
- 聊一下,前后分离后带来的跨域访问和cookie问题
在谈前后分离前,我们先看看什么是前后一体的.当我们用javaweb开发网站时,最终我们渲染的jsp或者springthymeleaf.我们的页面其实是WEB-INFO或者templates下.当用户请 ...
- 使用 Nginx 部署前后端分离项目,解决跨域问题
前后端分离这个问题其实松哥和大家聊过很多了,上周松哥把自己的两个开源项目部署在服务器上以帮助大家可以快速在线预览(喜大普奔,两个开源的 Spring Boot + Vue 前后端分离项目可以在线体验了 ...
- nodeJS(express4.x)+vue(vue-cli)构建前后端分离详细教程(带跨域)
好想再回到大学宿舍,当时床虽小,房随小,但是心确是满的 ----致 西安工程大学a-114舍友们 转载请注明出处:水车:http://www.cnblogs.com/xuange306/p/6185 ...
- ASP.NET WebApi+Vue前后端分离之允许启用跨域请求
前言: 这段时间接手了一个新需求,将一个ASP.NET MVC项目改成前后端分离项目.前端使用Vue,后端则是使用ASP.NET WebApi.在搭建完成前后端框架后,进行接口测试时发现了一个前后端分 ...
- 前后端分离下的CAS跨域流程分析
写在最前 前后端分离其实有两类: 开发阶段使用dev-server,生产阶段是打包成静态文件整个放入后端项目中. 开发阶段使用dev-server,生产阶段是打包成静态文件放入单独的静态资源服务器中, ...
- 08 Django REST Framework 解决前后端分离项目中的跨域问题
01-安装模块 pip install django-cors-headers 02-添加到INSTALL_APPS中 INSTALLED_APPS = ( ... 'corsheaders', .. ...
- lf 前后端分离 (3) 中间建跨域
一.关于中间建跨域 为了减少跨域代码冗余,采用中间件 from django.utils.deprecation import MiddlewareMixin class CorsMiddleware ...
随机推荐
- A - Wrestling Match HDU - 5971
Nowadays, at least one wrestling match is held every year in our country. There are a lot of people ...
- jquery.editable-select 可编辑下拉框之获取select值和input值
使用jquery.editable-select可以实现可编辑下拉框的功能,但需要先导入jquery.js,jquery.editable-select.css,jquery.editable-sel ...
- 基于.net的通用内存缓存模型组件
谈到缓存,我们自然而然就会想到缓存的好处,比如: 降低高并发数据读取的系统压力:静态数据访问.动态数据访问 存储预处理数据,提升系统响应速度和TPS 降低高并发数据写入的系统压力 提升系统可用性,后台 ...
- Servlet的理解
一.什么是Servlet? Servlet是用Java编写的web组件,实际上可以简单的理解为是用来处理请求的,为什么这么说,看了它的生命周期就知道了. 二.常见的Servlet容器 4容器顾名思义是 ...
- How to Quickly Create a Copy of a Table using Transact-SQL
The easiest way to create a copy of a table is to use a Transact-SQL command. Use SELECT INTO to ext ...
- mysql 读写分离
常见的读写分离方案:1)Amoeba读写分离2)MySQL-Proxy读写分离3)基于程序读写分离(效率很高,实施难度大,开发改代码) 2)原理 web 访问数据库,通过proxy4040端口作为转发 ...
- 【ThinkPHP框架学习 】(2) --- 后台管理系统如何用iframe点击左边右边局部刷新
如题: 在写后台管理系统时,需要实现后台界面的局部动态刷新. 左边的导航栏使用a标签进行设置,通过href和target属性的配合,就可以将iframe中的子页实现动态 ...
- 零基础如何迅速学习HTML5?新手小白学习web前端H5自白!
很多的人在毕业之后才发现原来学的专业不是自己想做的工作,或者专业对口的工作待遇让人觉得并不满意,于是很多人选择培训机构学新的一门技能转换行业.IT行业的web前端H5受到很多学员的青睐.那么学习web ...
- CentOS配置上网
CentOS设置: 进入CentOS命令模式: Centos7更改默认启动桌面(或命令行)模式 vi /etc/inittab:查看启动文件,在该文件中存在两种方式: multi-user.tar ...
- 页面第一次加载,JS没有效果,刷新一下就好了
问题详述:页面跳转的时候,第一个第二个页面都没有问题,跳到第三个页面,JS脚本没有起作用,刷新一下就好了. 1.猜测:第一个页面和第二个页面的JS,会对第三个页面产生影响,(因为之前没有这个问题,只改 ...