运用cors解决跨域问题总结

最近在做的一个应用迁移项目,第一阶段要将工作台页面内的a应用所有链接,迁到b应用中,对应链接的域名也变为b应用的域名,因此产生了跨域问题。通常这种跨域问题可以采用jsonp请求解决,但是jsonp在本项目中会有几个难点:一是前端改动较大,二是jsonp只支持get请求,另外就是比较难执行灰度(jsonp和非jsonp的请求显然是不好作为灰度的A/B项的)。
    除了jsonp,还有一种比较新的技术就是cors了。CORS是一种允许当前域(domain)的资源(比如html/js/web service)被其他域(domain)的脚本请求访问的机制。使用CORS,可以通过普通的XMLHttpRequest发起请求和获得数据,并且支持各种类型请求。缺点就是因为属于比较新的技术,所以浏览器兼容性有一定局限。

      由于这次改造的工作台只支持火狐和谷歌浏览器,所以cors的兼容性也就不是问题。如果是其他pc端的系统,在选择cors是就要考虑兼容性的影响了。

      下面就是具体怎么实现cors。首先,对于支持cors的浏览器,发送请求时,如果我们观察请求头会发现带有"Origin:http://example.taobao.com" ,该标识用来说明本次请求来自的域。要实现cors,只要在服务端在响应头部加上标识“Access-Control-Allow-Origin:http://example.taobao.com”,这样浏览器发现Access-Control-Allow-Origin和请求来自的域一致,就允许跨域访问资源example.taobao.com的资源了。对应服务端代码:
rundata.getResponse().setHeader("Access-Control-Allow-Origin", "http://example.taobao.com");             
      如果Access-Control-Allow-Origin设置为"*",那么任何域的请求都可以通过cors访问服务资源,但是这样显然不够安全。我们可以在服务端设置一个域白名单,收到请求时先取请求头中origin标识的域,判断域是否在白名单中,如果在的话,再将该域设置到响应的Access-Control-Allow-Origin中。这样就实现指定某些域cors请求服务资源。
      服务端返回的响应除了加允许的请求域标识,同时对允许的请求方法也要标识,我们一般固定写为get和post就可以:  rundata.getResponse().setHeader("Access-Control-Allow-Methods","GET,POST");
      同时需要设置:
      rundata.getResponse().setHeader("Access-Control-Allow-Headers", rundata.getRequest().getHeader("access-control-request-headers"));//意思是请求的headers是什么我就返回允许的headers什么
      需要注意的时,按照上面方法做,此时的cors请求可以访问服务,但是请求不会带cookie信息。如果需要cookie信息的话,需要请求js和服务端做一个通信验证:
      js请求: var invocation = new XMLHttpRequest();  invocation.withCredentials = true;        
      服务端:rundata.getResponse().setHeader("Access-Control-Allow-Credentials", "true");      
      该验证IE并不支持,即使是高版本支持cors的IE10,11,所以这也是个坑。需要兼容ie的应用基本不用考虑cors了。
      最后,需要说的是cors的一个重要特性,处理不好也是一个坑,就是探测请求。当跨域请求时,如果请求较为“复杂”(定义复杂的标准在最后会附上),则浏览器会先发一个OPTIONS类型请求,域名和uri不变,但是不会带任何参数和cookie信息。这个请求的目的就是获得返回的响应后验证响应头,判断服务端是否支持该域的cors访问,支持的话才会发送真正的请求。所以叫探测请求。那么我们在服务端对这种OPTIONS类型方法请求,显然要特殊处理,首先按照前面介绍设置响应头相关内容以支持cors,其次要让请求跳过执行业务方法直接返回结束,因为这只是个探寻请求。这块我们可以做一个公用模块,或拦截器来统一处理:
      if("OPTIONS".equals(rundata.getRequest().getMethod())){
        //设置Access-Control-Allow相关头
        rundata.getResponse().getWriter().flush();
        return true;
      }
如果不希望每次请求都多一次OPTIONS请求,可以设置返回响应头信息:
      rundata.getResponse().setHeader("Access-Control-Max-Age","60"); //缓存OPTIONS结果60秒

最后附上cors“复杂”请求标准(满足一条即是):
      1、http请求方法不是HEAD、GET、POST其中之一
      2、http请求头没有包含下列所有:accept、accept-language、content-language、last-event-id、content-type
      3、content-type不是下列类型:application/x-www-form-urlencoded、multipart/form-data、text/plain

时间: 2025-01-19 18:59:30

运用cors解决跨域问题总结的相关文章

一步一步学习SignalR进行实时通信_3_通过CORS解决跨域

原文:一步一步学习SignalR进行实时通信_3_通过CORS解决跨域 一步一步学习SignalR进行实时通信\_3_通过CORS解决跨域 SignalR 一步一步学习SignalR进行实时通信_3_通过CORS解决跨域 前言 关于start()的补充 跨域解决方案 JSONP CORS CORS跨域演示 结束语 参考文献 前言 这周工作比较忙,一直没有时间学习SignalR,大致希望一周能写一篇关于SignalR的文章.上一篇用Persistent Connections方式实现了个简单的在线

js前端解决跨域问题的8种方案(最新最全)_javascript技巧

1.同源策略如下: URL 说明 是否允许通信 http://www.a.com/a.jshttp://www.a.com/b.js 同一域名下 允许 http://www.a.com/lab/a.jshttp://www.a.com/script/b.js 同一域名下不同文件夹 允许 http://www.a.com:8000/a.js http://www.a.com/b.js 同一域名,不同端口 不允许 http://www.a.com/a.js https://www.a.com/b.j

纯前端解决跨域问题

背景 跨域是由浏览器的同源策略引起的,是指页面请求的url地址,必须与浏览器上的url地址处于同域上(即域名,端口,协议相同). 这是为了防止某域名下的接口被其他域名下的网页非法调用,是浏览器对JavaScript施加的安全限制. 这个措施的出发点是好的,但是程序页面开发的过程中,却常常给前端开发者带来麻烦. 由于前端开发过程中,静态资源是放在本地电脑上的,访问这些资源通常通过IP方式(127.0.0.1)或者localhosts来访问,与线上服务器所在域名不符,不能顺利调用服务的端口. 解决跨

Python框架Django解决跨域API调用问题

前几天,在做质量度量平台时(Python框架Django开发),跨域调用的问题,我前面有一个做法是,在本地server中增加一个API,这个API的功能是远程请求一个API并解析数据,这样浏览器访问本系统时只需要调用同域名下新增加的这个API即可,不存在跨域问题.不过,这次我想直接在AngularJS中调用跨域的远程API. 解决跨域问题,有两个方法:1.使用jsonp 2.使CORS生效 使用jsonp方法,需要让服务器端放回jsonp格式的response,如Django可以加jsonp相关

js中利用JSONP解决跨域问题

什么是跨域? 简单的来说,出于安全方面的考虑,javascript不能访问其他服务器上的内容,即"同源策略"(参考1,参考2).跨域就是通过某种手段绕过同源策略去访问不同服务器上的内容.只要域名.端口.协议任何一个不同,就是不同的域.协议或端口不同只能通过后端来解决. URL 说明 是否允许通信 http://www.a.com/a.js http://www.a.com/b.js 同一域名下 允许 http://www.a.com/lab/a.js http://www.a.com/

window.name解决跨域数据传输问题

原文:http://research.microsoft.com/~helenw/papers/subspace.pdf window.name 传输技术,原本是 Thomas Frank 用于解决 cookie 的一些劣势(每个域名 4 x 20 Kb 的限制.数据只能是字符串.设置和获取 cookie 语法的复杂等等)而发明的(详细见原文:<Session variables without cookies>),后来 Kris Zyp 在此方法的基础上强化了 window.name 传输

在liferay中用serveResource解决跨域访问问题

简介: 众所周知,跨域问题是十分常见的需求,比如让客户端的ext-js控件可以渲染来自服务器端的json对象.我们可以用很多很多方法来解决,比如jsonP.但是,在liferay中,我们可以用serveResource方法来优雅的解决跨域访问问题. 白板分析: 以下是摘自我在技术讨论会上的白板: 解决方法: 首先编写一段serveResource方法,让其和远端的json对象打交道,它作为中间层可以封装来在远程的json资源,然后提供给本域内的ext-js代码来渲染. 当然了,这里我们的资源必须

node js-php应用80端口,使用node.js通过8888端口实现即时推送,怎么解决跨域问题?

问题描述 php应用80端口,使用node.js通过8888端口实现即时推送,怎么解决跨域问题? 项目背景是一个php应用.为了加入即时推送功能,使用node.js写了8888端口用于推送即时消息,并使用socket.io进行数据传输. 如何解决80端口应用页面跨域与8888端口建立socket连接问题?

html2canvas截图如何解决跨域的问题?

问题描述 html2canvas截图如何解决跨域的问题? 1.问题描述 如果不跨域的话,截图正常. 如果有跨域的图片,那么js报错,报错信息如下: Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported. 2.代码 /** * 截图 */ function doScreenShot(){ html2canvas(docume