背景

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 前后端分离后引起的跨域访问解决方案的更多相关文章

  1. 解决前后端分离后的Cookie跨域问题

    一. 前端Ajax关键配置 $.ajax({ type: "post", url: xxx, data: xxx, contentType: 'application/json', ...

  2. vue+springboot前后端分离实现单点登录跨域问题处理

    最近在做一个后台管理系统,前端是用时下火热的vue.js,后台是基于springboot的.因为后台系统没有登录功能,但是公司要求统一登录,登录认证统一使用.net项目组的认证系统.那就意味着做单点登 ...

  3. 聊一下,前后分离后带来的跨域访问和cookie问题

    在谈前后分离前,我们先看看什么是前后一体的.当我们用javaweb开发网站时,最终我们渲染的jsp或者springthymeleaf.我们的页面其实是WEB-INFO或者templates下.当用户请 ...

  4. 使用 Nginx 部署前后端分离项目,解决跨域问题

    前后端分离这个问题其实松哥和大家聊过很多了,上周松哥把自己的两个开源项目部署在服务器上以帮助大家可以快速在线预览(喜大普奔,两个开源的 Spring Boot + Vue 前后端分离项目可以在线体验了 ...

  5. nodeJS(express4.x)+vue(vue-cli)构建前后端分离详细教程(带跨域)

    好想再回到大学宿舍,当时床虽小,房随小,但是心确是满的 ----致  西安工程大学a-114舍友们 转载请注明出处:水车:http://www.cnblogs.com/xuange306/p/6185 ...

  6. ASP.NET WebApi+Vue前后端分离之允许启用跨域请求

    前言: 这段时间接手了一个新需求,将一个ASP.NET MVC项目改成前后端分离项目.前端使用Vue,后端则是使用ASP.NET WebApi.在搭建完成前后端框架后,进行接口测试时发现了一个前后端分 ...

  7. 前后端分离下的CAS跨域流程分析

    写在最前 前后端分离其实有两类: 开发阶段使用dev-server,生产阶段是打包成静态文件整个放入后端项目中. 开发阶段使用dev-server,生产阶段是打包成静态文件放入单独的静态资源服务器中, ...

  8. 08 Django REST Framework 解决前后端分离项目中的跨域问题

    01-安装模块 pip install django-cors-headers 02-添加到INSTALL_APPS中 INSTALLED_APPS = ( ... 'corsheaders', .. ...

  9. lf 前后端分离 (3) 中间建跨域

    一.关于中间建跨域 为了减少跨域代码冗余,采用中间件 from django.utils.deprecation import MiddlewareMixin class CorsMiddleware ...

随机推荐

  1. 微信小程序图片放大预览

    需求:当点击图片时,当前图片放大预览,且可以左右滑动 实现方式:使用微信小程序图片预览接口 我们可以看到api需要两个参数,分别通过下面的data-list和data-src来传到js中 wxml代码 ...

  2. android开发第一天

    今天可以说是我正式投入android怀抱的第一天吧,按着自己的兴趣,努力地吸取知识.听了程老师的课,也觉得收获很多,毕竟以前都是看着书本或者网页教程来学习,第一次有人这么直接地跟你教授着,说着一些你听 ...

  3. 三种方式打印杨辉三角形(JAVA实现)

    //采用一个二维数组打印杨辉三角 class Yanghui1 { public static void main(String[] args) { //设置杨辉三角的行数 int num = 10; ...

  4. NTP时间服务器 搭建

    1.1 NTP简介 NTP(Network Time Protocol,网络时间协议)是用来使网络中的各个计算机时间同步的一种协议.它的用途是把计算机的时钟同步到世界协调时UTC,其精度在局域网内可达 ...

  5. $.grep()函数

    定义和用法 $.grep() 函数使用指定的函数过滤数组中的元素,并返回过滤后的数组. 提示:源数组不会受到影响,过滤结果只反映在返回的结果数组中. 语法 $.grep( array, functio ...

  6. Java中的Redis应用

    1.配置redis集群   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?xml version="1.0" encoding ...

  7. 坦言spring中事务、重试、异步执行注解

    一.@Transaction 我们再编码过程中,大量使用到这个注解.一般情况下,@Transaction使用默认注解可以完成90%的功能,下面会针对一些特殊场景下,@Tansaction的使用注意 1 ...

  8. 71、django之Ajax续

    接上篇随笔.继续介绍ajax的使用. 上篇友情连接:http://www.cnblogs.com/liluning/p/7831169.html 本篇导航: Ajax响应参数 csrf 跨站请求伪造 ...

  9. windows中更换Jdk版本不生效

    本机已经安装了jdk1.7,而比较早期的项目需要依赖jdk1.6,于是同时在本机安装了jdk1.6和jdk1.7. 安装jdk1.6前,执行java -version得到 C:\Users\liuxi ...

  10. vimgdb安装以及使用

    vimgdb安装 vim-7.3.tar.bz2http://www.vim.org/sources.phpvimgdb-for-vim7.3 (this patch) https://github. ...