写在前面
跨域问题是 javascript 在同源策略下产生的,javascript 只能访问和操作自己所在域的资源(相同协议、主机名、端口号)。
在以前,前端代码和后端代码混杂在一起,javascript 直接调用系统里面统一的 Httphandler 这样是不存在跨域问题的。但随着现在技术的发展,多客户端、前后端分离等开发环境使得 javascript 使用到跨域获取数据的情况越来越多,所以,下面来说说 javascript 跨域要怎么实现。
需要说明的是,同源策略是 javascript 里面的限制,其他语言如 c#、java 是可以调用其他 webserver 的。
传统的跨域解决方案是 JSONP(JSON with padding) 和 CORS(Cross-origin resource sharing),其中,JSONP 需要客户端和服务端一起配合,CORS 则只需要在服务端进行处理就可以了。
JSONP
在同源策略下,某个服务器是没有办法获取到服务器以外的数据的,iframe,img,script等标签是例外,这些标签可以通过 src 属性去请求其他服务器上的资源,JSONP 就是利用到了 script 标签的 src 来调用跨域的请求。
举例如下:服务端和客户端约定传一个名为 callback 的参数来使用 JSONP 功能,比如常规的请求地址如下:
1 | http://www.example.net/sample.aspx |
该地址的返回结果可能是一个单纯的 json 字符串,比如:
1 | { foo: 'bar' } |
当加上 callback 的参数之后,即开启 JSONP 功能的时候。
1 | http://www.example.net/sample.aspx?callback=mycallback |
服务端会使用传入的 callback 参数对返回的数据进行处理:
1 | mycallback({ foo: 'bar' }) |
这样子就能够获取到跨域的数据同时使用本域的回调函数进行处理。
JSONP 跨域方式比较方便,也支持各种比较老的浏览器,但是缺点很明显,只支持 GET 的方式提交,GET 方式对请求的参数长度有限制,有些情况下可能不满足需求。
CORS(Cross-origin resource sharing)同域安全策略
CORS 同域安全策略是 W3C 在05年提出的跨域资源请求机制,它要求在当前域的相应报头添加 Access-Control-Allow-Origin 标签,从而允许该域的站点访问当前域上的资源。
服务器端在返回的相应报头中添加 Access-Control-Allow-Origin 的标签,该标签的值可为 URL 或 * ,星号表示允许所有域访问当前域。
1 | // 服务器端配置 |
对应域的客户端只需要正常的发出 GET 或 POST 请求即可获取到返回的 OK 信息。
1 | // 浏览器端使用 |
要注意的是,CORS 默认只支持 GET/POST 这两种 http 请求类型,要开启 PUT/DELETE 这两种方式的话需要在响应报头添加 Access-Control-Allow-Methods 标签。
1 | // 服务器端配置 |
不过 CORS 的缺点是对浏览器的版本有要求,不是所有版本的浏览器都支持,
XDR-IE8
IE8 不支持 OCRS,不过它引入了 XDR特性来实现 CORS 的部分规范(IE11 不再支持 XDR 特性),由于 XDR 使用得很少,具体介绍可查看原文
HTML5解决方案
WebSocket
WebSocket protocol 是 HTML5 一种新的协议,实现了浏览器和服务器的全双工通信,也允许跨域通讯,是 server push 技术的一种很好体现。
1 | // 客户端-原生 webSocket 实现 |
服务端继续使用 Node.js 来编写,并使用 socket.io 模块辅助,它封装了 webSocket 接口,并对不支持 webSocket 的浏览器提供了向下兼容(如替代为 Flash Socket/Comet)。
服务端要先安装 socket.io 模块
1 | // 服务端脚本 |
但 socket.io 提供的接口与原生的有所区别:
1 | <!-- 客户端-socket.io 实现 --> |
webSocket 在使用 socket.io 来解决兼容之后,能够很好地摆脱无状态的 http 连接,更好的处理连接断开、数据错误等情况。