跨域是一个在前端开拓中常常碰着的问题。它指的是浏览器不能实行其他网站的脚本,这是由于浏览器的同源策略造成的。所谓同源,即协议、域名、端口都要相同。只要这三个要素中有任何一个不同,都被当作是不同的域,就会产生跨域问题。
同源策略是浏览器最核心也最基本的安全功能。如果短缺了同源策略,浏览器很随意马虎受到 XSS、CSFR 等攻击。同源策略详细限定内容包括:
例如,假设有两个网站,A 网站支配在 http://localhost:81,B 网站支配在 http://localhost:82。当 A 网站的页面想去访问 B 网站的信息时,就会涌现跨域问题。由于它们的端口不同,不知足同源策略的哀求。

总之,同源策略的存在是为了保护用户的安全和隐私,但在某些情形下,也给开拓带来了一些寻衅。开拓职员须要理解跨域问题的实质,并节制一些办理跨域问题的方法,以确保运用程序的正常运行。
二、跨域要求办法大揭秘(一)JSONP 跨域JSONP 是利用浏览器对 <script> 的资源引用没有同源限定这一特点来实现跨域要求。其事理是浏览器端动态天生 <script> 标签来要求后台供应数据的接口,并定义好用于吸收相应数据的函数,同时将函数名通过要求参数提交给后台。做事器端吸收到要求处理产生结果数据后,返回一个函数调用的 js 代码,并将结果数据作为实参传入到回调函数中。浏览器端收到相应后自动实行函数调用的 js 代码,即实行了提前定义好的回调函数,便得到了所须要的结果数据。
优点是对浏览器的支持较好,尤其支持老式浏览器。缺陷是只能办理 GET 类型的 ajax 跨域要求,其他类型的跨域要求并不能处理;缺点处理机制并不完善,无法进行缺点处理。
前后端合营的代码示例:
前端 AJAX 要求:
$.ajax({ url: "http://otherdomain.com/manage/role/get", async: false, type: "get", dataType: "jsonp", data: { "id": 1 }, jsonp: "callback", jsonpCallback:"fn", success: function(data){ alert(data.code); }, error: function(){ alert('fail'); }})
后端相应数据:
@RequestMapping("/manage/role/get")@ResponseBodypublic String get(HttpServletRequest request, HttpServletResponse response) { BaseOutput outPut = new BaseOutput(); try { QueryFilter filter = new QueryFilter(request); logger.info(filter.toString()); String id = filter.getParam().get(MainConst.KEY_ID); if(!StringUtil.isEmpty(id)) { ImRole role = roleService.getByPk(filter); outPut.setData(role); } else { outPut.setCode(OutputCodeConst.INPUT_PARAM_IS_NOT_FULL); outPut.setMsg("The get id is needed."); } } catch (Exception e) { logger.error("获取角色数据非常!
(二)nginx 反向代理
", e); outPut.setCode(OutputCodeConst.UNKNOWN_ERROR); outPut.setMsg("获取角色数据非常!
" + e.getMessage()); } return "fn("+JsonUtil.objectToJson(outPut)+")";}
nginx 反向代理办理跨域的事理是将 nginx 安装在本地,将项目支配于 nginx 下,通过反向代理的办法访问后台做事器。当浏览器发起要求时,由于要求的域名、协议、端口与 nginx 做事器相同,知足同源策略,从而避免了跨域问题。
须要进行的额外配置情形如下:
下载并安装 nginx。在 nginx.conf 文件中进行配置,例如配置本地 web 项目访问路径和反向代理。server { listen 80; server_name localhost; location/ { root myApp/mobile; index index.html index.htm; } location/remote-interface/{ proxy_pass http://remote-address/remote-interface/ ; }}
通过 PHP 端修正 header 可以办理跨域问题。可以在文件 header 里设置 ACCESS-CONTROL-ALLOW-ORIGIN,许可特定域名或所有域名访问。
设置办法如下:
许可全部的域名访问header("Access-Control-Allow-Origin:");
许可指定域名访问
header('Access-Control-Allow-Origin:http://a.test.com');
(四)document.domain 跨子域
利用 document.domain 可以办理不同域的两个页面之间 JavaScript 交互操作限定。此方案仅限于跨子域的运用处景,两个页面通过设置 document.domain 为根本主域,从而实现同域。
例如:
// A 页面:http://www.example.com/a.html// B 页面:http://example.com/b.html// 当 A、B 想要获取对方的 cookie 或者 DOM 节点时,可以设置:document.domain='example.com';
(五)CORS 跨域
CORS(Cross-Origin Resource Sharing),即跨域资源共享。其事理是利用浏览器自动添加一些附加的头信息来实现跨域要求。做事器端通过返回特定的相应头来掌握是否赞许跨域要求。
做事器端相应头设置:
指定许可其他域名访问Access-Control-Allow-Origin:// 值要么是要求时 Origin 字段的值,要么是一个 ,表示接管任意域名的要求。
是否许可后续要求携带认证信息(cookies)
Access-Control-Allow-Credentials:true // 值是一个布尔值,表示是否许可发送 Cookie。
预检结果缓存韶光
Access-Control-Max-Age: 1800
许可的要求类型
Access-Control-Allow-Methods:GET,POST,PUT,POST
许可的要求头字段
Access-Control-Allow-Headers:x-requested-with,content-type
如果要在跨域要求中带上 cookie,须要知足 3 个条件:
web(浏览器)要求设置 withCredentials 为 true。做事器设置首部字段 Access-Control-Allow-Credentials 为 true。做事器的 Access-Control-Allow-Origin 不能为 。(六)图片 ping 或 script 标签跨域图片 ping 和 script 标签跨域的办法是利用浏览器许可加载不同源的图片和脚本的特点来实现跨域数据通报。特点是大略易用,但缺陷是只能进行单向的数据通报,且无法获取相应内容。
(七)window.name + iframe通过 window.name 和 iframe 结合实现跨域的事理是在页面中动态创建一个 iframe 页面指向另一个域,将数据赋值给 iframe 的 window.name 属性,然后将 iframe 的 src 指向相同域的空缺页面,之后再将 iframe 删除,就可以在当前页面获取到跨域的数据。
代码实现过程:
var proxy = function(url, callback) { var state = 0; var iframe = document.createElement('iframe'); iframe.src = url; iframe.onload = function() { if (state ===1) { callback(iframe.contentWindow.name); destoryFrame(); } else if (state ===0) { iframe.contentWindow.location = 'http://www.domain.com/aa.html'; state = 1; } }; document.body.appendChild(iframe);};
postMessage 是 HTML5 XMLHttpRequest Level 2 中的 API,它可以用于不同窗口之间的通报,包括跨域数据通报。
事理是通过 postMessage(data, origin) 方法,接管两个参数:data(要发送的数据,可以是任意基本类型或可复制的工具,但部分浏览器只支持字符串,以是传参时最好用 JSON.stringify() 序列化)和 origin(协议 + 域名 + 端口号,也可以设置为 "",表示可以通报给任意窗口,如果要指定和当前窗口同源的话,设置为 "/")。
例如:
在父页面中嵌入子页面,通过 postMessage 发送数据。
// parent.com/index.htmlwindow.onload = function() { var ifr = document.getElementById('ifr'); var targetOrigin = 'http://child.com'; ifr.contentWindow.postMessage('I was there!', targetOrigin);};
在子页面中通过 message 事宜监听父页面发送来的并显示。
// child.com/index.htmlwindow.addEventListener('message', function(event){ if (event.origin == 'http://parent.com') { alert(event.data); alert(event.source); }, false);};
(九)websocket
websocket 作为跨域办理方案的事理是通过建立一个持久化的连接,使得客户端和做事器可以双向通信,不受同源策略的限定。
代码实现如下:
var socket = new WebSocket('ws://otherdomain.com/socket');socket.onopen = function() { socket.send('Hello from client!');};socket.onmessage = function(event) { console.log('Received message from server: ' + event.data);};
(十)Node 中间件代理
Node 中间件代理办理跨域的事理是在 Node.js 做事器端设置一个代理,将客户真个要求转发到目标做事器,然后将目标做事器的相应返回给客户端。这样,对付客户端来说,要求看起来就像是来自同一个域。
代码示例:
const express = require('express');const request = require('request');const app = express();app.use('/proxy', function(req, res) { request('http://otherdomain.com' + req.url).pipe(res);});app.listen(3000, function() { console.log('Proxy server running on port 3000');});
(十一)nginx 反向代理
再次强调 nginx 反向代理办理跨域的事理是通过将本地的要求转发到不同域的做事器上,同时知足浏览器的同源策略,从而避免跨域问题。其上风在于配置相对大略,不须要对前端代码进行大量修正,并且可以同时期理多个不同域的做事器。