您好,欢迎访问一九零五行业门户网

Spring通过CROS协议解决跨域问题

现在接手学校网络中心的一个项目,根据团队成员的实际情况以及开发需要,老师希望做到前后端完全分离。后台使用java提供restful api 作为核心,前台无论pc或者移动端可以共用一个核心。前期解决了哦oauth2,作为授权机制等问题,本以为大业将成。(最近打算详细介绍一下机遇spring sercurity 实现oauth2的解决方案)结果又出现了一个跨域问题,让我们踩了一个大坑,记录在此,以绝后患。
错误信息如下:
response to preflight request doesn't pass access control check: no 'access-control-allow-origin' header is present on the requested resource. origin 'null' is therefore not allowed access. the response had http status code 403.
什么是跨域
简单的说即为浏览器限制访问a站点下的js代码对b站点下的url进行ajax请求。比如说,前端域名是www.abc.com,那么在当前环境中运行的js代码,出于安全考虑,访问www.xyz.com域名下的资源,是受到限制的。现代浏览器默认都会基于安全原因而阻止跨域的ajax请求,这是现代浏览器中必备的功能,但是往往给开发带来不便。特别是对我这样后台开发人员来讲,这个事情简直神奇。
但跨域的需求却一直都在,为了跨域,勤劳勇敢的程序猿们想出了许许多多的方法,例如,jsonp、代理文件等等。但这些做法增加了许多不必要的维护成本,而且应用场景也有许多限制,例如jsonp并非xhr,所以jsonp只能使用get传递参数。更详细的资料可以看这里 web应用跨域访问解决方案汇总
cors协议
如今的js大有一统天下的趋势,浏览器已经成了大多应用最好的安身之所。哪怕在移动端也有各种hybird方案,在本地文件系统的web页面,也有需要获取外部数据的需求,而这些需求也必然是跨域的。在寻找跨域解决方案时,发现了最优雅解决方案就是html5来带了的“cross-origin resource sharing”的新特性,来赋予开发者权力决定资源是否允许被跨域访问。
cors是一个w3c标准,全称是”跨域资源共享”(cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出xmlhttprequest请求,从而克服了ajax只能同源使用的限制。
为什么说它优雅呢?
整个cors通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,cors通信与同源的ajax通信没有差别,代码完全一样。浏览器一旦发现ajax请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现cors通信的关键是服务器。 只要服务器实现了cors接口 ,就可以跨源通信。
解决这个问题的关键就落在了我这个负责后台的程序猿身上。
看看文档也不是什么难事嘛,就是需要在http头中设置access-control-allow-origin来决定需要允许哪些站点来访问。关于cros协议更详细内容参考 跨域资源共享 cors 详解
cros常见header
cors具有以下常见的header
access-control-allow-origin: http://kbiao.me access-control-max-age: 3628800 access-control-allow-methods: get,put, delete access-control-allow-headers: content-type
“access-control-allow-origin”表明它允许”http://kbiao.me “发起跨域请求
“access-control-max-age”表明在3628800秒内,不需要再发送 预检验 请求,可以缓存该结果(上面的资料上我们知道cros协议中,一个ajax请求被分成了第一步的 option 预检测请求和正式请求)
“access-control-allow-methods”表明它允许get、put、delete的外域请求
“access-control-allow-headers”表明它允许跨域请求包含content-type头
当然在处理这个问题的时候前端也有不少坑,特别是chrome浏览器不允许localhost的跨域请求,详细方案见我项目中负责前端解决方案的小伙伴。 假装有链接
常规解决方案
知道了问题的原因,也知道了配套的解决办法,现在就让我们来实现解决。思路很简单,当前端要请求跨域资源时候,我们给它加上响应的响应头即可。很显然我们自己定义一个过滤器是最简单不过了。
/** * created by kangb on 2016/5/10. */ @component public class mycorsfilter implements filter { @override public void init(filterconfig filterconfig) throws servletexception { } @override public void dofilter(servletrequest servletrequest, servletresponse servletresponse, filterchain filterchain) throws ioexception, servletexception { httpservletresponse response = (httpservletresponse) servletresponse; string origin = (string) servletrequest.getremotehost()+":"+servletrequest.getremoteport(); 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,authorization"); response.setheader("access-control-allow-credentials","true"); filterchain.dofilter(servletrequest, servletresponse); } @override public void destroy() { } }
@component 是spring的注解,关键部分在dofilter中,添加了我们需要的头, option 是预检测需要所以需要允许, authorization 是做了oauth2登录响应所必须的, access-control-allow-credentials 表示允许cookies。都是根据自己项目的实际需要配置。
再配置web.xml使得过滤器生效
<filter> <filter-name>cors</filter-name> <filter-class>·class_path·.myecorsfilter</filter-class> </filter> <filter-mapping> <filter-name>cors</filter-name> <url-pattern>/api/*</url-pattern> </filter-mapping>
接下来前端就可以像往常一样使用ajax请求获得资源了,完全不需要做出什么改变。
spring 4中更优雅的办法
springmvc4提供了非常方便的实现跨域的方法。在requestmapping中使用注解。
@crossorigin(origins = “http://kbiao.me”)
全局实现 .定义类继承webmvcconfigureradapter,设置跨域相关的配置
public class corsconfigureradapter extends webmvcconfigureradapter{ @override public void addcorsmappings(corsregistry registry) { registry.addmapping("/api/*").allowedorigins("*"); } }
将该类注入到容器中:
<bean class="com.tmall.wireless.angel.web.config.corsconfigureradapter"></bean>
其它类似信息

推荐信息