背景

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. 学习笔记TF060:图像语音结合,看图说话

    斯坦福大学人工智能实验室李飞飞教授,实现人工智能3要素:语法(syntax).语义(semantics).推理(inference).语言.视觉.通过语法(语言语法解析.视觉三维结构解析)和语义(语言 ...

  2. Linux上MySQL的安装

    a.检测是否安装了mysql rpm  -qa | grep mysql b.卸载系统自带的mysql rpm -e --nodeps 卸载的包 rpm -e --nodeps mysql-libs- ...

  3. Photoshop颜色出现比较大的偏差,偏色严重,显示器配置文件2351似乎有问题

    其实出现这个问题是因为 显示器的配置问题.并不是PS版本或者电脑系统问题. 一般在你首次启动PS的时候会出现提示:显示器配置文件2351似乎有问题. 如果你点击了继续运行那以后你使用PS打开任何文件都 ...

  4. day4--老Word模板使用指南

    Word常用快捷键 Ctrl + 1 一级标题 Ctrl + 2 二级标题 Ctrl + 3 三级标题 Ctrl + 5 代码块输入 Ctrl + 6 正文输入 专业的排版,一定要规范,目录,生成目录

  5. C#定时任务采用线程和队列实现

    构思:写一个全局的Queue ,  然后开一个线程去循环. 不善言语,直接看代码吧! );    }}

  6. R语言高性能编程(三)

    一.使用并行计算加倍提升性能1.数据并行 VS 任务并行实现数据并行的算法scoket 并行性注意并行计算时间并不与执行任务的计算资源数目成正比(计算机核心),amdahl定律:并行代码的速度受限于串 ...

  7. matplotlib删除x轴

    组内有个同事,有个奇怪的需求需要matplotlib删除x轴 效果图如下:

  8. 如何用Python写一个计算器软件 附带效果图

    该计算器使用Python  tkinter模块开发 效果如下图 import tkinter #导入tkinter模块 root = tkinter.Tk() root.minsize(280,500 ...

  9. Mac OS X更新VirtualBox以后Genymotion无法启动的一种情况

    这两天VirtualBox更新到5.0了,于是乎就升级了.结果升级后就中了个大奖,Genymotion起不来了.我用的是Genymotion 2.5,不久前刚升级的,因为官网打不开,不知是不是最新版. ...

  10. Unity3D获取资源的方法整理:

    在使用Unity3D做项目时,获取资源的方法大致分为两种.一种是通过写代码的方式,在程序运行时,自动获取资源:一种是通过手动拖拽的方式进行获取.不管是什么类型的资源都能通过这两种方式获得,下面拿图片资 ...